zf

zenflows testing
git clone https://s.sonu.ch/~srfsh/zf.git
Log | Files | Refs | Submodules | README | LICENSE

telemetry.ex (2934B)


      1 defmodule Plug.Telemetry do
      2   @moduledoc """
      3   A plug to instrument the pipeline with `:telemetry` events.
      4 
      5   When plugged, the event prefix is a required option:
      6 
      7       plug Plug.Telemetry, event_prefix: [:my, :plug]
      8 
      9   In the example above, two events will be emitted:
     10 
     11     * `[:my, :plug, :start]` - emitted when the plug is invoked.
     12       The event carries the `system_time` as measurement. The metadata
     13       is the whole `Plug.Conn` under the `:conn` key and any leftover
     14       options given to the plug under `:options`.
     15 
     16     * `[:my, :plug, :stop]` - emitted right before the request is sent.
     17       The event carries a single measurement, `:duration`,  which is the
     18       monotonic time difference between the stop and start events.
     19       It has the same metadata as the start event, except the connection
     20       has been updated.
     21 
     22   Note this plug measures the time between its invocation until a response
     23   is sent. The `:stop` event is not guaranteed to be emitted in all error
     24   cases, so this Plug cannot be used as a Telemetry span.
     25 
     26   ## Time unit
     27 
     28   The `:duration` measurements are presented in the `:native` time unit.
     29   You can read more about it in the docs for `System.convert_time_unit/3`.
     30 
     31   ## Example
     32 
     33       defmodule InstrumentedPlug do
     34         use Plug.Router
     35 
     36         plug :match
     37         plug Plug.Telemetry, event_prefix: [:my, :plug]
     38         plug Plug.Parsers, parsers: [:urlencoded, :multipart]
     39         plug :dispatch
     40 
     41         get "/" do
     42           send_resp(conn, 200, "Hello, world!")
     43         end
     44       end
     45 
     46   In this example, the stop event's `duration` includes the time
     47   it takes to parse the request, dispatch it to the correct handler,
     48   and execute the handler. The events are not emitted for requests
     49   not matching any handlers, since the plug is placed after the match plug.
     50   """
     51 
     52   @behaviour Plug
     53 
     54   @impl true
     55   def init(opts) do
     56     {event_prefix, opts} = Keyword.pop(opts, :event_prefix)
     57 
     58     unless event_prefix do
     59       raise ArgumentError, ":event_prefix is required"
     60     end
     61 
     62     ensure_valid_event_prefix!(event_prefix)
     63     start_event = event_prefix ++ [:start]
     64     stop_event = event_prefix ++ [:stop]
     65     {start_event, stop_event, opts}
     66   end
     67 
     68   @impl true
     69   def call(conn, {start_event, stop_event, opts}) do
     70     start_time = System.monotonic_time()
     71     metadata = %{conn: conn, options: opts}
     72     :telemetry.execute(start_event, %{system_time: System.system_time()}, metadata)
     73 
     74     Plug.Conn.register_before_send(conn, fn conn ->
     75       duration = System.monotonic_time() - start_time
     76       :telemetry.execute(stop_event, %{duration: duration}, %{conn: conn, options: opts})
     77       conn
     78     end)
     79   end
     80 
     81   defp ensure_valid_event_prefix!(event_prefix) do
     82     if is_list(event_prefix) && Enum.all?(event_prefix, &is_atom/1) do
     83       :ok
     84     else
     85       raise ArgumentError,
     86             "expected :event_prefix to be a list of atoms, got: #{inspect(event_prefix)}"
     87     end
     88   end
     89 end