[Tesla middleware] `non_error_statuses` option (#154)

* [Tesla middleware] `non_error_statuses` option

* :mark_status_ok option instead of :non_error_statuses

---------

Co-authored-by: Tristan Sloughter <t@crashfast.com>
This commit is contained in:
Andrey Chernykh 2023-04-21 18:07:21 +02:00 committed by GitHub
parent 19a44fbd68
commit 1230271580
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 77 additions and 3 deletions

View File

@ -12,7 +12,8 @@ defmodule Tesla.Middleware.OpenTelemetry do
- `:span_name` - override span name. Can be a `String` for a static span name, - `: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` 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 alias OpenTelemetry.SemanticConventions.Trace
@ -27,6 +28,7 @@ defmodule Tesla.Middleware.OpenTelemetry do
OpenTelemetry.Tracer.with_span span_name, %{kind: :client} do OpenTelemetry.Tracer.with_span span_name, %{kind: :client} do
env env
|> maybe_put_additional_ok_statuses(opts[:mark_status_ok])
|> Tesla.put_headers(:otel_propagator_text_map.inject([])) |> Tesla.put_headers(:otel_propagator_text_map.inject([]))
|> Tesla.run(next) |> Tesla.run(next)
|> set_span_attributes() |> set_span_attributes()
@ -49,6 +51,15 @@ defmodule Tesla.Middleware.OpenTelemetry do
end end
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 defp set_span_attributes({_, %Tesla.Env{} = env} = result) do
OpenTelemetry.Tracer.set_attributes(build_attrs(env)) OpenTelemetry.Tracer.set_attributes(build_attrs(env))
@ -59,8 +70,13 @@ defmodule Tesla.Middleware.OpenTelemetry do
result result
end end
defp handle_result({:ok, %Tesla.Env{status: status} = env}) when status >= 400 do defp handle_result({:ok, %Tesla.Env{status: status, opts: opts} = env}) when status >= 400 do
OpenTelemetry.Tracer.set_status(OpenTelemetry.status(:error, "")) 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} {:ok, env}
end end

View File

@ -289,6 +289,64 @@ defmodule Tesla.Middleware.OpenTelemetryTest do
assert_receive {:span, span(status: {:status, :error, ""})} assert_receive {:span, span(status: {:status, :error, ""})}
end 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 test "Appends query string parameters to http.url attribute", %{bypass: bypass} do
defmodule TestClient do defmodule TestClient do
def get(client, id) do def get(client, id) do