ReqTele (ReqTele v0.1.2)

Copy Markdown View Source

Req plugin to instrument requests with :telemetry events.

Usage

Preferably, ReqTele should be the last plugin attached to your %Req.Request{}. This allows ReqTele to emit events both at the very start and very end of the request and response pipelines. In this way, you can observe both the total time spent issuing and processing the request and response, as well as the time spent only with the request adapter.

req = Req.new() |> ReqTele.attach()

req =
  Req.new(adapter: &my_adapter/1)
  |> ReqSomeOtherThing.attach()
  |> ReqTele.attach()

Events

ReqTele produces the following events (in order of event dispatch):

  • [:req, :request, :pipeline, :start]
  • [:req, :request, :adapter, :start]
  • [:req, :request, :adapter, :stop]
  • [:req, :request, :adapter, :error]
  • [:req, :request, :pipeline, :stop]
  • [:req, :request, :pipeline, :error]

You can configure ReqTele to produce only :pipeline or :adapter events; see ReqTele.attach/2 for options.

Logging

ReqTele defines a simple, default logger that logs basic request information and timing.

Here's how a successful request might be logged:

Req:479128347 - GET https://example.org (pipeline)
Req:479128347 - GET https://example.org (adapter)
Req:479128347 - 200 in 403ms (adapter)
Req:479128347 - 200 in 413ms (pipeline)

For usage and configuration, see ReqTele.attach_default_logger/1.

Summary

Functions

Installs request, response, and error steps that emit :telemetry events.

Attach a basic telemetry event handler that logs ReqTele events.

Returns a list of events emitted by ReqTele.

Types

option()

@type option() :: {:adapter, boolean()} | {:pipeline, boolean()} | {:metadata, map()}

options()

@type options() :: boolean() | [option()]

Functions

attach(req, opts \\ [])

@spec attach(Req.Request.t(), options()) :: Req.Request.t()

Installs request, response, and error steps that emit :telemetry events.

Options

  • :pipeline (default true) - emit pipeline telemetry events
  • :adapter (default true) - emit adapter telemetry events
  • :metadata (default nil) - map of user-supplied metadata available in telemetry handlers

As a shortcut, all events can be suppressed by passing false instead of an options list.

These same options can also be passed through Req options under the :telemetry key to change the behavior on a per-request basis. Maps of metadata will be merged. For example:

req = Req.new() |> ReqTele.attach(metadata: %{api_version: 1})

Req.get!(req,
  url: "https://api.example.org/endpoint",
  telemetry: [metadata: %{endpoint: "endpoint"}]
)

# Your telemetry event handler will have access to the merged map
def handle_event(
  [:req, _, _, _],
  _measurements,
  %{metadata: %{api_version: v, endpoint: e}},
  _config
) do
  # ...
end

Examples

Emit all events by default, limiting them per-request as needed.

req = Req.new() |> ReqTele.attach()

# Emits all events
Req.get!(req, url: "https://example.org")

# Do not emit events
Req.get!(req, url: "https://example.org", telemetry: false)

# Emit adapter events but not pipeline events
Req.get!(req, url: "https://example.org", telemetry: [pipeline: false])

Suppress all events by default, enabling them per-request as needed.

req = Req.new() |> ReqTele.attach(false)

# Will not emit events
Req.get!(req, url: "https://example.org")

# Override to emit events
Req.get!(req, url: "https://example.org", telemetry: true)

# Override to emit only adapter events
Req.get!(req, url: "https://example.org", telemetry: [adapter: true])

Finally, suppress only a certain kind of event by default, overriding that default as needed.

req = Req.new() |> ReqTele.attach(pipeline: false)

# Will only emit adapter events
Req.get!(req, url: "https://example.org")

# Override to emit only pipeline events
Req.get!(req, url: "https://example.org", telemetry: [pipeline: true, adapter: false])

attach_default_logger(kind_or_events \\ :all)

@spec attach_default_logger(
  :all
  | :adapter
  | :pipeline
  | [:telemetry.event_name(), ...]
) ::
  :ok | {:error, :already_exists}

Attach a basic telemetry event handler that logs ReqTele events.

Usage

Telemetry event handlers can be attached in your application's start/2 callback:

@impl true
def start(_type, _args) do
  ReqTele.attach_default_logger()

  children = [
    ...
  ]

  Supervisor.start_link(...)
end

All events are logged by default, but this can be overridden by passing in a keyword describing the kind of events to log or a list of specific events to log.

# Logs all events
:ok = ReqTele.attach_default_logger()

# Logs only adapter events
:ok = ReqTele.attach_default_logger(:adapter)

# Logs only pipeline errors
:ok = ReqTele.attach_default_logger([[:req, :request, :pipeline, :error]])

Example

Here's what a successful request might look like:

15:52:01.462 [info] Req:479128347 - GET https://example.org (pipeline)
15:52:01.466 [info] Req:479128347 - GET https://example.org (adapter)
15:52:01.869 [info] Req:479128347 - 200 in 403ms (adapter)
15:52:01.875 [info] Req:479128347 - 200 in 413ms (pipeline)

And here's what an error might look like:

15:52:04.174 [error] Req:42446822 - ERROR in 2012ms (adapter)
%Finch.Error{reason: :request_timeout}

events(kind \\ :all)

@spec events(:all | :pipeline | :adapter) :: [:telemetry.event_name(), ...]

Returns a list of events emitted by ReqTele.