Skip to content

Bandit: Add the request_path to the span name#401

Closed
joshk wants to merge 1 commit intoopen-telemetry:mainfrom
joshk:friendly-bandit-span-name
Closed

Bandit: Add the request_path to the span name#401
joshk wants to merge 1 commit intoopen-telemetry:mainfrom
joshk:friendly-bandit-span-name

Conversation

@joshk
Copy link
Copy Markdown

@joshk joshk commented Oct 27, 2024

The Phoenix instrumentation updates the span name to include the request_path, but some requests don't go through the router (like LiveView websocket connections), which means the root span is missing context for what the span is related to.

This PR changes the default Bandit span name to include the conn.request_path.

The Phoenix instrumentation updates the span name to include the `request_path`, but some requests don't go through the router (like LiveView websocket connections), which means the root span is missing context for what the span is related to.
@tsloughter
Copy link
Copy Markdown
Member

The reason it is only set when going through the router is that it can't have a high cardinality value for the span name: https://github.com/open-telemetry/semantic-conventions/blob/main/docs/http/http-spans.md#name

If the user wants the path, no matter what, in the name then it can be set with the update_name macro in their handler.

Or if there is something about being routed to a LiveView that means it is a low cardinality value then it could be updated by the instrumentation there?

@joshk
Copy link
Copy Markdown
Author

joshk commented Oct 28, 2024

Hi @tsloughter , thanks for the comment and information.

I agree with you, this PR would be going against the high cardinality rule for span names.

While update_name is a great general solution, it doesn't work for sockets defined in Phoenix endpoints. eg.

socket("/live", Phoenix.LiveView.Socket, websocket: [connect_info: [session: @session_options]])

socket("/socket", NervesHubWeb.UserSocket, websocket: [connect_info: [session: @session_options]])

Is there a recommended approach to updating a parent spans name? This would work for the case of the second socket, which is in our code base, but not for the socket used for Live View communications.

@joshk
Copy link
Copy Markdown
Author

joshk commented Oct 28, 2024

A slightly different approach would be to update the span name only if the status code is 101.

eg. if conn.status == 101, do: Tracer.update_name("WEBSOCKET #{conn.request_path}")

This would be done in handle_request_stop/3

@joshk
Copy link
Copy Markdown
Author

joshk commented Oct 28, 2024

@tsloughter
Copy link
Copy Markdown
Member

@joshk what about checking if the path is /live? Instead of checking for the 101.

@joshk
Copy link
Copy Markdown
Author

joshk commented Oct 28, 2024

@tsloughter great advice!

I checked the URL patterns for Phoenix websocket connections, and they all end with /websocket, so I changed my customization to use request_path, https://github.com/nerves-hub/nerves_hub_web/pull/1612/files#diff-a90641c8be89f7c4fa30427d348f740fc6a884d91c446fdc5987b78a92dcb8e5R16-R22

I think having this in the Phoenix instrumentation would be useful, but there is no telemetry event to hook into, which is why I ended up using the Bandit [:bandit, :request, :stop] event.

@joshk
Copy link
Copy Markdown
Author

joshk commented Oct 28, 2024

@tsloughter , thank you for your reviews and advice.

@joshk joshk closed this Oct 28, 2024
@tsloughter
Copy link
Copy Markdown
Member

I think having this in the Phoenix instrumentation would be useful,

aah, wonder why Phoenix doesn't send a telemetry event for these...

@joshk
Copy link
Copy Markdown
Author

joshk commented Oct 28, 2024

Yeah, its a little odd and annoying, and I'm sure they would be open to a PR, but I'll delay looking into that until another day.

@danschultzer
Copy link
Copy Markdown
Contributor

I'm trying to figure out if we can do something upstream to be able to attach to sockets: phoenixframework/phoenix#6019

lunks added a commit to lunks/opentelemetry-erlang-contrib that referenced this pull request Mar 6, 2026
Bandit created HTTP server spans with atom names (e.g. :GET) from semconv
values. The OTel spec requires span names to be strings. This changes
the initial span name to use conn.method (a string like "GET").

Additionally, at request completion, the span name is updated to include
the route template ("{method} {route}") when conn.private[:plug_route]
is available. This is set by Phoenix and other Plug-based routers during
dispatch, enabling proper span names without requiring opentelemetry_phoenix.

Follows up on open-telemetry#401 and the discussion about OTel HTTP semantic conventions
requiring span names to be "{method} {http.route}" when the route is known.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants