From c2cb6bc86cfecda17ef2edbb435fbf248bb0ca5e Mon Sep 17 00:00:00 2001 From: Andrea Leopardi Date: Thu, 11 Apr 2024 17:37:07 +0200 Subject: [PATCH] Improve docs and README for opentelemetr_ecto (#312) --- instrumentation/opentelemetry_ecto/README.md | 18 ++---- .../lib/opentelemetry_ecto.ex | 58 ++++++++++++++----- 2 files changed, 49 insertions(+), 27 deletions(-) diff --git a/instrumentation/opentelemetry_ecto/README.md b/instrumentation/opentelemetry_ecto/README.md index 22c968d..4c69440 100644 --- a/instrumentation/opentelemetry_ecto/README.md +++ b/instrumentation/opentelemetry_ecto/README.md @@ -1,24 +1,23 @@ # 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 estimates the start time of the span by subtracting the reported total duration from the current timestamp. -After installing, setup the handler in your application behaviour before your -top-level supervisor starts. +After installing, set up the handler in your application's `start/2` callback before your +top-level supervisor starts, passing the Telemetry prefix of the Ecto repo you want to instrument. ```elixir 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. ## Installation -If [available in Hex](https://hex.pm/docs/publish), the package can be installed -by adding `opentelemetry_ecto` to your list of dependencies in `mix.exs`: +Add the package to your list of dependencies in `mix.exs`: ```elixir def deps do @@ -30,7 +29,7 @@ end ## Compatibility Matrix -| OpentelemetryEcto Version | Otel Version | Notes | +| OpentelemetryEcto Version | OTel Version | Notes | | :------------------------ | :----------- | :---- | | | | | | 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.4 | v1.0.0-rc.4 | | | 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). - diff --git a/instrumentation/opentelemetry_ecto/lib/opentelemetry_ecto.ex b/instrumentation/opentelemetry_ecto/lib/opentelemetry_ecto.ex index c6f0513..93e0c3d 100644 --- a/instrumentation/opentelemetry_ecto/lib/opentelemetry_ecto.ex +++ b/instrumentation/opentelemetry_ecto/lib/opentelemetry_ecto.ex @@ -1,14 +1,15 @@ defmodule OpentelemetryEcto do @moduledoc """ - Telemetry handler for creating OpenTelemetry Spans from Ecto query events. Any - relation preloads, which are executed in parallel in separate tasks, will be + Telemetry handler for creating OpenTelemetry Spans from Ecto query events. + + 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: Tracer.with_span "parent span" do Repo.all(Query.from(User, preload: [:posts, :comments])) 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. > #### Note {: .neutral} @@ -19,35 +20,62 @@ defmodule OpentelemetryEcto do 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 """ - Attaches the OpentelemetryEcto handler to your repo events. This should be called - from your application behaviour on startup. + Attaches the `OpentelemetryEcto` handler to your repo events. - 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: * `:time_unit` - a time unit used to convert the values of query phase - timings, defaults to `:microsecond`. See `System.convert_time_unit/3` - * `:span_prefix` - the first part of the span name, as a `String.t`, - defaults to the concatenation of the event name with periods, e.g. + timings, defaults to `:microsecond`. See `System.convert_time_unit/3`. + * `:span_prefix` - the first part of the span name. + 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 - 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 are conflits with default provided attributes, the ones provided with this config will have precedence. - * `:db_statement` - :disabled (default) | :enabled | fun - Whether or not to include db statements. + * `:db_statement` - `:disabled` (default), `:enabled`, or a function. + 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 sanitized version of it. This is useful for removing sensitive information from the query string. Unless this option is `:enabled` or a function, 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] - :telemetry.attach({__MODULE__, event}, event, &__MODULE__.handle_event/4, config) + :telemetry.attach({__MODULE__, event}, event, &__MODULE__.handle_event/4, options) end @doc false