[opentelemetry_tesla] Conditionally override propagator (#176)

* Optionally disable trace propagation for Tesla

While we always want spans being produced, trace progation is not
desirable in all cases - namely, when calling external parties, as that
may leak sensitive information, like one present on Baggage.

This patch introduces a new option `:propagate`, that defaults to
`true`.

Some tweaks are made to existing propagation test, fixing how options
are used. The approach here is closer to what we see in some middleware
tests of Tesla itself.

* change to propagator override

* change propagator to it uses global default

* mix format

* improve docs

---------

Co-authored-by: Andrew Rosa <dev@andrewhr.io>
This commit is contained in:
Guilherme de Maio 2023-05-29 07:53:21 -03:00 committed by GitHub
parent 6a5fc4c884
commit 901b571b07
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 38 additions and 20 deletions

View File

@ -12,6 +12,9 @@ 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`
- `:propagator` - configures trace headers propagators. Setting it to `:none` disables propagation.
Any module that implements `:otel_propagator_text_map` can be used.
Defaults to calling `:otel_propagator_text_map.get_text_map_injector/0`
- `:mark_status_ok` - configures spans with a list of expected HTTP error codes to be marked as `ok`,
not as an error-containing spans
"""
@ -29,7 +32,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([]))
|> maybe_propagate(Keyword.get(opts, :propagator, :opentelemetry.get_text_map_injector()))
|> Tesla.run(next)
|> set_span_attributes()
|> handle_result()
@ -51,6 +54,16 @@ defmodule Tesla.Middleware.OpenTelemetry do
end
end
defp maybe_propagate(env, :none), do: env
defp maybe_propagate(env, propagator) do
:otel_propagator_text_map.inject(
propagator,
env,
fn key, value, env -> Tesla.put_header(env, key, value) 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)

View File

@ -491,27 +491,32 @@ defmodule Tesla.Middleware.OpenTelemetryTest do
assert response_size == byte_size(response)
end
test "Injects distributed tracing headers" do
OpentelemetryTelemetry.start_telemetry_span(
"tracer_id",
"my_label",
%{},
%{kind: :client}
)
assert {:ok,
%Tesla.Env{
headers: [
{"traceparent", traceparent}
]
}} =
Tesla.Middleware.OpenTelemetry.call(
_env = %Tesla.Env{url: ""},
_next = [],
_opts = []
)
describe "trace propagation" do
test "injects distributed tracing headers by default" do
{:ok, env} = Tesla.get(client(), "/propagate-traces")
assert traceparent = Tesla.get_header(env, "traceparent")
assert is_binary(traceparent)
assert_receive {:span, span(name: _name, attributes: attributes)}
assert %{"http.target": "/propagate-traces"} = :otel_attributes.map(attributes)
end
test "optionally disable propagation but keep span report" do
{:ok, env} = Tesla.get(client(propagator: :none), "/propagate-traces")
refute Tesla.get_header(env, "traceparent")
assert_receive {:span, span(name: _name, attributes: attributes)}
assert %{"http.target": "/propagate-traces"} = :otel_attributes.map(attributes)
end
end
defp client(opts \\ []) do
[
{Tesla.Middleware.OpenTelemetry, opts}
]
|> Tesla.client(fn env -> {:ok, env} end)
end
defp endpoint_url(port), do: "http://localhost:#{port}/"