Skip to content

Add :telemetry_prefix option to Tesla.Middleware.Telemetry #390

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 58 additions & 32 deletions lib/tesla/middleware/telemetry.ex
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,34 @@ if Code.ensure_loaded?(:telemetry) do
end)
```

## Options
- `:telemetry_prefix` - replaces default `[:tesla]` with desired Telemetry event prefix (see below)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this option is passed directly to telemetry middleware I don't think we need to include the telemetry_ prefix in the prefix name (🥁)

I'd go with just :prefix .

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good. Will update.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just updated. Let me know if that works.


## Custom Telemetry Prefix

All events will use a `:telemetry_prefix` which defaults to `[:tesla]`.

You can customize events by providing your own `:telemetry_prefix` locally:

```
defmodule MyClient do
use Tesla

plug Tesla.Middleware.Telemetry, telemetry_prefix: [:custom, :prefix]

end

:telemetry.attach("my-tesla-telemetry", [:custom, :prefix, :request, :stop], fn event, measurements, meta, config ->
# Do something with the event
end)
```

You can configure `:telemetry_prefix` globally in your config, but if set the `:telemetry_prefix` option will override:

```
config :tesla, Tesla.Middleware.Telemetry, telemetry_prefix: [:custom, :prefix]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is a good idea - it would override this all clients from all dependencies.

Since the use case comes from building API clients as packages I think it would be better to hide tesla from end user and use this instead.

# config/config.exs
config :myclient, telemetry_prefix: [...]

# myclient.ex

defmodule Myclient do
  use Tesla
  @compile_config Application.compile_env(:myclient, :telemetry_prefix, [])
  plug Tesla.Middleware.Telemetry, prefix: Keyword.get(@compile_config, :prefix, [:myclient])
  # ...
end

# or top provide runtime configuration

defmodule Myclient do
  def new do
    config = Application.get_env(:myclient, :telemetry_prefix, [])
    middleware = [
      # ...
      {Tesla.Middleware.Telemetry, prefix: Keyword.get(@compile_config, :prefix, [:myclient])}
    ]

    Tesla.client(middleware, adapter)
  end
end

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense. I kept going back and forth on globalizing. Will remove and update.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just updated. Let me know if that works.

```

## Telemetry Events

* `[:tesla, :request, :start]` - emitted at the beginning of the request.
Expand Down Expand Up @@ -46,11 +74,14 @@ if Code.ensure_loaded?(:telemetry) do

@behaviour Tesla.Middleware

@default_telemetry_prefix [:tesla]

@impl Tesla.Middleware
def call(env, next, _opts) do
def call(env, next, opts) do
start_time = System.monotonic_time()
prefix = telemetry_prefix(opts)

emit_start(%{env: env})
emit_start(%{env: env}, prefix)

try do
Tesla.run(env, next)
Expand All @@ -59,62 +90,57 @@ if Code.ensure_loaded?(:telemetry) do
stacktrace = System.stacktrace()
duration = System.monotonic_time() - start_time

emit_exception(duration, %{kind: kind, reason: reason, stacktrace: stacktrace})
emit_exception(duration, %{kind: kind, reason: reason, stacktrace: stacktrace}, prefix)

:erlang.raise(kind, reason, stacktrace)
else
{:ok, env} = result ->
duration = System.monotonic_time() - start_time

emit_stop(duration, %{env: env})
emit_legacy_event(duration, result)
emit_stop(duration, %{env: env}, prefix)
emit_legacy_event(duration, result, prefix)

result

{:error, reason} = result ->
duration = System.monotonic_time() - start_time

emit_stop(duration, %{env: env, error: reason})
emit_legacy_event(duration, result)
emit_stop(duration, %{env: env, error: reason}, prefix)
emit_legacy_event(duration, result, prefix)

result
end
end

defp emit_start(metadata) do
:telemetry.execute(
[:tesla, :request, :start],
%{system_time: System.system_time()},
metadata
)
defp config, do: Application.get_env(:tesla, __MODULE__, [])

defp telemetry_prefix(opts) do
with nil <- Keyword.get(opts, :telemetry_prefix) do
Keyword.get(config(), :telemetry_prefix, @default_telemetry_prefix)
end
end

defp emit_start(metadata, prefix) do
event = prefix ++ [:request, :start]
:telemetry.execute(event, %{system_time: System.system_time()}, metadata)
end

defp emit_stop(duration, metadata) do
:telemetry.execute(
[:tesla, :request, :stop],
%{duration: duration},
metadata
)
defp emit_stop(duration, metadata, prefix) do
event = prefix ++ [:request, :stop]
:telemetry.execute(event, %{duration: duration}, metadata)
end

defp emit_legacy_event(duration, result) do
defp emit_legacy_event(duration, result, prefix) do
if !@disable_legacy_event do
event = prefix ++ [:request]
duration_µs = System.convert_time_unit(duration, :native, :microsecond)

:telemetry.execute(
[:tesla, :request],
%{request_time: duration_µs},
%{result: result}
)
:telemetry.execute(event, %{request_time: duration_µs}, %{result: result})
end
end

defp emit_exception(duration, metadata) do
:telemetry.execute(
[:tesla, :request, :exception],
%{duration: duration},
metadata
)
defp emit_exception(duration, metadata, prefix) do
event = prefix ++ [:request, :exception]
:telemetry.execute(event, %{duration: duration}, metadata)
end
end
end
Loading