Improve docs and README for opentelemetr_ecto (#312)

This commit is contained in:
Andrea Leopardi 2024-04-11 17:37:07 +02:00 committed by GitHub
parent 3f13bc8b20
commit c2cb6bc86c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 49 additions and 27 deletions

View File

@ -1,24 +1,23 @@
# OpentelemetryEcto # OpentelemetryEcto
Telemetry handler that creates Opentelemetry spans from Ecto query events. Because Telemetry handler that creates OpenTelemetry spans from Ecto query events. Because
Ecto emits telemetry events only after queries have finished, OpentelemetryEcto Ecto emits telemetry events only after queries have finished, OpentelemetryEcto
estimates the start time of the span by subtracting the reported total duration estimates the start time of the span by subtracting the reported total duration
from the current timestamp. from the current timestamp.
After installing, setup the handler in your application behaviour before your After installing, set up the handler in your application's `start/2` callback before your
top-level supervisor starts. top-level supervisor starts, passing the Telemetry prefix of the Ecto repo you want to instrument.
```elixir ```elixir
OpentelemetryEcto.setup([:blog, :repo]) OpentelemetryEcto.setup([:blog, :repo])
``` ```
See the documentation for `OpentelemetryEcto.setup/2` for additional options that See [the documentation for `OpentelemetryEcto.setup/2`](https://hexdocs.pm/opentelemetry_ecto/OpentelemetryEcto.html#setup/2) for additional options that
may be supplied. may be supplied.
## Installation ## Installation
If [available in Hex](https://hex.pm/docs/publish), the package can be installed Add the package to your list of dependencies in `mix.exs`:
by adding `opentelemetry_ecto` to your list of dependencies in `mix.exs`:
```elixir ```elixir
def deps do def deps do
@ -30,7 +29,7 @@ end
## Compatibility Matrix ## Compatibility Matrix
| OpentelemetryEcto Version | Otel Version | Notes | | OpentelemetryEcto Version | OTel Version | Notes |
| :------------------------ | :----------- | :---- | | :------------------------ | :----------- | :---- |
| | | | | | | |
| v0.1.0 | <= v.0.5.0 | | | v0.1.0 | <= v.0.5.0 | |
@ -39,8 +38,3 @@ end
| v1.0.0-rc.3 | v1.0.0-rc.3 | | | v1.0.0-rc.3 | v1.0.0-rc.3 | |
| v1.0.0-rc.4 | v1.0.0-rc.4 | | | v1.0.0-rc.4 | v1.0.0-rc.4 | |
| v1.0 | v1.0 | | | v1.0 | v1.0 | |
Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
be found at [https://hexdocs.pm/opentelemetry_ecto](https://hexdocs.pm/opentelemetry_ecto).

View File

@ -1,14 +1,15 @@
defmodule OpentelemetryEcto do defmodule OpentelemetryEcto do
@moduledoc """ @moduledoc """
Telemetry handler for creating OpenTelemetry Spans from Ecto query events. Any Telemetry handler for creating OpenTelemetry Spans from Ecto query events.
relation preloads, which are executed in parallel in separate tasks, will be
Any relation preloads, which are executed in parallel in separate tasks, will be
linked to the span of the process that initiated the call. For example: linked to the span of the process that initiated the call. For example:
Tracer.with_span "parent span" do Tracer.with_span "parent span" do
Repo.all(Query.from(User, preload: [:posts, :comments])) Repo.all(Query.from(User, preload: [:posts, :comments]))
end end
this will create a span called "parent span" with three child spans for each This will create a span called `"parent span:"` with three child spans for each
query: users, posts, and comments. query: users, posts, and comments.
> #### Note {: .neutral} > #### Note {: .neutral}
@ -19,35 +20,62 @@ defmodule OpentelemetryEcto do
require OpenTelemetry.Tracer require OpenTelemetry.Tracer
@typedoc """
Option that you can pass to `setup/2`.
"""
@typedoc since: "1.3.0"
@type setup_option() ::
{:time_unit, System.time_unit()}
| {:span_prefix, String.t()}
| {:additional_attributes, %{String.t() => term()}}
| {:db_statement, :enabled | :disabled | (String.t() -> String.t())}
@doc """ @doc """
Attaches the OpentelemetryEcto handler to your repo events. This should be called Attaches the `OpentelemetryEcto` handler to your repo events.
from your application behaviour on startup.
Example: This should be called from your application's `c:Application.start/2` callback on startup,
before starting the application's top-level supervisor.
OpentelemetryEcto.setup([:blog, :repo]) `event_prefix` must be the prefix configured in the `Ecto.Repo` Telemetry configuration.
By default, it's the snake-cased name of the repository module. For `MyApp.Repo`, it would
be `[:my_app, :repo]`.
For example:
@impl Application
def start(_type, _args) do
OpentelemetryEcto.setup([:blog, :repo])
children = [...]
Supervisor.start_link(children, strategy: :one_for_one)
end
## Options
You may also supply the following options in the second argument: You may also supply the following options in the second argument:
* `:time_unit` - a time unit used to convert the values of query phase * `:time_unit` - a time unit used to convert the values of query phase
timings, defaults to `:microsecond`. See `System.convert_time_unit/3` timings, defaults to `:microsecond`. See `System.convert_time_unit/3`.
* `:span_prefix` - the first part of the span name, as a `String.t`, * `:span_prefix` - the first part of the span name.
defaults to the concatenation of the event name with periods, e.g. Defaults to the concatenation of the event name with periods, such as
`"blog.repo.query"`. This will always be followed with a colon and the `"blog.repo.query"`. This will always be followed with a colon and the
source (the table name for SQL adapters). source (the table name for SQL adapters). For example: `"blog.repo.query:users"`.
* `:additional_attributes` - additional attributes to include in the span. If there * `:additional_attributes` - additional attributes to include in the span. If there
are conflits with default provided attributes, the ones provided with are conflits with default provided attributes, the ones provided with
this config will have precedence. this config will have precedence.
* `:db_statement` - :disabled (default) | :enabled | fun * `:db_statement` - `:disabled` (default), `:enabled`, or a function.
Whether or not to include db statements. Whether or not to include DB statements in the **span attributes** (as the
`db.statement` attribute).
Optionally provide a function that takes a query string and returns a Optionally provide a function that takes a query string and returns a
sanitized version of it. This is useful for removing sensitive information from the sanitized version of it. This is useful for removing sensitive information from the
query string. Unless this option is `:enabled` or a function, query string. Unless this option is `:enabled` or a function,
query statements will not be recorded on spans. query statements will not be recorded on spans.
""" """
def setup(event_prefix, config \\ []) do @spec setup(:telemetry.event_name(), [setup_option()]) :: :ok | {:error, :already_exists}
def setup(event_prefix, options \\ []) when is_list(options) do
event = event_prefix ++ [:query] event = event_prefix ++ [:query]
:telemetry.attach({__MODULE__, event}, event, &__MODULE__.handle_event/4, config) :telemetry.attach({__MODULE__, event}, event, &__MODULE__.handle_event/4, options)
end end
@doc false @doc false