Skip to content

Commit

Permalink
[Tesla middleware] non_error_statuses option (#154)
Browse files Browse the repository at this point in the history
* [Tesla middleware] `non_error_statuses` option

* :mark_status_ok option instead of :non_error_statuses

---------

Co-authored-by: Tristan Sloughter <t@crashfast.com>
  • Loading branch information
implicitly-awesome and tsloughter authored Apr 21, 2023
1 parent 19a44fb commit 1230271
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ defmodule Tesla.Middleware.OpenTelemetry do
- `:span_name` - override span name. Can be a `String` for a static span name,
or a function that takes the `Tesla.Env` and returns a `String`
- `:mark_status_ok` - configures spans with a list of expected HTTP error codes to be marked as `ok`,
not as an error-containing spans
"""

alias OpenTelemetry.SemanticConventions.Trace
Expand All @@ -27,6 +28,7 @@ defmodule Tesla.Middleware.OpenTelemetry do

OpenTelemetry.Tracer.with_span span_name, %{kind: :client} do
env
|> maybe_put_additional_ok_statuses(opts[:mark_status_ok])
|> Tesla.put_headers(:otel_propagator_text_map.inject([]))
|> Tesla.run(next)
|> set_span_attributes()
Expand All @@ -49,6 +51,15 @@ defmodule Tesla.Middleware.OpenTelemetry do
end
end

defp maybe_put_additional_ok_statuses(env, [_ | _] = additional_ok_statuses) do
case env.opts[:additional_ok_statuses] do
nil -> Tesla.put_opt(env, :additional_ok_statuses, additional_ok_statuses)
_ -> env
end
end

defp maybe_put_additional_ok_statuses(env, _additional_ok_statuses), do: env

defp set_span_attributes({_, %Tesla.Env{} = env} = result) do
OpenTelemetry.Tracer.set_attributes(build_attrs(env))

Expand All @@ -59,8 +70,13 @@ defmodule Tesla.Middleware.OpenTelemetry do
result
end

defp handle_result({:ok, %Tesla.Env{status: status} = env}) when status >= 400 do
OpenTelemetry.Tracer.set_status(OpenTelemetry.status(:error, ""))
defp handle_result({:ok, %Tesla.Env{status: status, opts: opts} = env}) when status >= 400 do
span_status =
if status in Keyword.get(opts, :additional_ok_statuses, []), do: :ok, else: :error

span_status
|> OpenTelemetry.status("")
|> OpenTelemetry.Tracer.set_status()

{:ok, env}
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,64 @@ defmodule Tesla.Middleware.OpenTelemetryTest do
assert_receive {:span, span(status: {:status, :error, ""})}
end

test "Marks Span status as :error if error status is within `mark_status_ok` opt list",
%{bypass: bypass} do
defmodule TestClient do
def get(client) do
Tesla.get(client, "/users/")
end

def client(url) do
middleware = [
{Tesla.Middleware.BaseUrl, url},
{Tesla.Middleware.OpenTelemetry, mark_status_ok: [404]}
]

Tesla.client(middleware)
end
end

Bypass.expect_once(bypass, "GET", "/users", fn conn ->
Plug.Conn.resp(conn, 404, "")
end)

bypass.port
|> endpoint_url()
|> TestClient.client()
|> TestClient.get()

assert_receive {:span, span(status: {:status, :ok, ""})}
end

test "Marks Span status as :ok unless error status is within `mark_status_ok` opt list",
%{bypass: bypass} do
defmodule TestClient do
def get(client) do
Tesla.get(client, "/users/")
end

def client(url) do
middleware = [
{Tesla.Middleware.BaseUrl, url},
{Tesla.Middleware.OpenTelemetry, mark_status_ok: []}
]

Tesla.client(middleware)
end
end

Bypass.expect_once(bypass, "GET", "/users", fn conn ->
Plug.Conn.resp(conn, 404, "")
end)

bypass.port
|> endpoint_url()
|> TestClient.client()
|> TestClient.get()

assert_receive {:span, span(status: {:status, :error, ""})}
end

test "Appends query string parameters to http.url attribute", %{bypass: bypass} do
defmodule TestClient do
def get(client, id) do
Expand Down

0 comments on commit 1230271

Please sign in to comment.