zf

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

README.md (7266B)


      1 # Telemetry
      2 
      3 [![Codecov](https://codecov.io/gh/beam-telemetry/telemetry/branch/master/graphs/badge.svg)](https://codecov.io/gh/beam-telemetry/telemetry/branch/master/graphs/badge.svg)
      4 
      5 [Documentation](https://hexdocs.pm/telemetry/)
      6 
      7 Telemetry is a lightweight library for dynamic dispatching of events, with a focus on
      8 metrics and instrumentation. Any Erlang or Elixir library can use `telemetry` to emit
      9 events. Application code and other libraries can then hook into those events and run
     10 custom handlers.
     11 
     12 > Note: this library is agnostic to tooling and therefore is not directly related to
     13 > OpenTelemetry. For OpenTelemetry in the Erlang VM, see
     14 > [opentelemetry-erlang](https://github.com/open-telemetry/opentelemetry-erlang), and check
     15 > [opentelemetry_telemetry](https://github.com/opentelemetry-beam/opentelemetry_telemetry)
     16 > to connect both libraries.
     17 
     18 ## Usage
     19 
     20 In a nutshell, you register a custom module and function to be invoked for certain events,
     21 which are executed whenever there is such an event. The event name is a list of atoms. Each event is
     22 composed of a numeric value and can have metadata attached to it. Let's look at an example.
     23 
     24 Imagine that you have a web application and you'd like to log latency and response status for each
     25 incoming request. With Telemetry, you can build a module which does exactly that whenever a response
     26 is sent. The first step is to execute a measurement.
     27 
     28 In Elixir:
     29 
     30 ```elixir
     31 :telemetry.execute(
     32   [:web, :request, :done],
     33   %{latency: latency},
     34   %{request_path: path, status_code: status}
     35 )
     36 ```
     37 
     38 In Erlang:
     39 
     40 ```erlang
     41 telemetry:execute(
     42   [web, request, done],
     43   #{latency => Latency},
     44   #{request_path => Path, status_code => Status}
     45 )
     46 ```
     47 
     48 Then you can create a module to be invoked whenever the event happens.
     49 
     50 In Elixir:
     51 
     52 ```elixir
     53 defmodule LogResponseHandler do
     54   require Logger
     55 
     56   def handle_event([:web, :request, :done], measurements, metadata, _config) do
     57     Logger.info(
     58       "[#{metadata.request_path}] #{metadata.status_code} sent in #{measurements.latency}"
     59     )
     60   end
     61 end
     62 ```
     63 
     64 In Erlang:
     65 
     66 ```erlang
     67 -module(log_response_handler).
     68 
     69 -include_lib("kernel/include/logger.hrl").
     70 
     71 handle_event([web, request, done], #{latency := Latency}, #{request_path := Path,
     72                                                             status_code := Status}, _Config) ->
     73   ?LOG_INFO("[~s] ~p sent in ~p", [Path, Status, Latency]).
     74 
     75 ```
     76 
     77 **Important note:**
     78 
     79 The `handle_event` callback of each handler is invoked synchronously on each `telemetry:execute` call.
     80 Therefore, it is extremely important to avoid blocking operations. If you need to perform any action
     81 that is not immediate, consider offloading the work to a separate process (or a pool of processes)
     82 by sending a message.
     83 
     84 Finally, all you need to do is to attach the module to the executed event.
     85 
     86 In Elixir:
     87 
     88 ```elixir
     89 :ok =
     90   :telemetry.attach(
     91     # unique handler id
     92     "log-response-handler",
     93     [:web, :request, :done],
     94     &LogResponseHandler.handle_event/4,
     95     nil
     96   )
     97 ```
     98 
     99 In Erlang:
    100 
    101 ```erlang
    102 ok = telemetry:attach(
    103   %% unique handler id
    104   <<"log-response-handler">>,
    105   [web, request, done],
    106   fun log_response_handler:handle_event/4,
    107   []
    108 )
    109 ```
    110 
    111 You might think that it isn't very useful, because you could just as well write a log statement
    112 instead of calling `telemetry:execute/3` – and you would be right! But now imagine that each Elixir library
    113 would publish its own set of events with information useful for introspection. Currently each library
    114 rolls their own instrumentation layer – Telemetry aims to provide a single interface for these use
    115 cases across the whole ecosystem.
    116 
    117 ### Spans
    118 
    119 In order to provide uniform events that capture the start and end of discrete events, it is recommended
    120 that you use the `telemetry:span/3` call. This function will generate a start event and a stop or exception
    121 event depending on whether the provided function executed successfully or raised an error. Under the hood,
    122 the `telemetry:span/3` function leverages the `telemetry:execute/3` function, so all the same usage patterns
    123 apply. If an exception does occur, an `EventPrefix ++ [exception]` event will be emitted and the caught error
    124 will be re-raised.
    125 
    126 The measurements for the `EventPrefix ++ [start]` event will contain a key called `system_time` which is
    127 derived by calling `erlang:system_time()`. For `EventPrefix ++ [stop]` and `EventPrefix ++ [exception]`
    128 events, the measurements will contain a key called `duration` and its value is derived by calling
    129 `erlang:monotonic_time() - StartMonotonicTime`. All events include a `monotonic_time` measurement too.
    130 All of them represent time as native units.
    131 
    132 To convert the duration from native units you can use:
    133 
    134 ```elixir
    135 milliseconds = System.convert_time_unit(duration, :native, :millisecond)
    136 ```
    137 
    138 To create span events you would do something like this:
    139 
    140 In Elixir:
    141 
    142 ```elixir
    143 def process_message(message) do
    144   start_metadata = %{message: message}
    145 
    146   result =
    147     :telemetry.span(
    148       [:worker, :processing],
    149       start_metadata,
    150       fn ->
    151         result = ... # Process the message
    152         {result, %{metadata: "Information related to the processing of the message"}}
    153       end
    154     )
    155 end
    156 ```
    157 
    158 In Erlang:
    159 
    160 ```erlang
    161 process_message(Message) ->
    162   StartMetadata =  #{message => Message},
    163   Result = telemetry:span(
    164     [worker, processing],
    165     StartMetadata,
    166     fun() ->
    167       Result = % Process the message
    168       {Result, #{metadata => "Information related to the processing of the message"}}
    169     end
    170   ).
    171 ```
    172 
    173 To then attach to the events that `telemetry:span/3` emits you would do the following:
    174 
    175 In Elixir:
    176 
    177 ```elixir
    178 :ok =
    179   :telemetry.attach_many(
    180     "log-response-handler",
    181     [
    182       [:worker, :processing, :start],
    183       [:worker, :processing, :stop],
    184       [:worker, :processing, :exception]
    185     ],
    186     &LogResponseHandler.handle_event/4,
    187     nil
    188   )
    189 ```
    190 
    191 In Erlang:
    192 
    193 ```erlang
    194 ok = telemetry:attach_many(
    195   <<"log-response-handler">>,
    196   [
    197     [worker, processing, start],
    198     [worker, processing, stop],
    199     [worker, processing, exception]
    200   ],
    201   fun log_response_handler:handle_event/4,
    202   []
    203 )
    204 ```
    205 
    206 With the following event handler module defined:
    207 
    208 In Elixir:
    209 
    210 ```elixir
    211 defmodule LogResponseHandler do
    212   require Logger
    213 
    214   def handle_event(event, measurements, metadata, _config) do
    215     Logger.info("Event: #{inspect(event)}")
    216     Logger.info("Measurements: #{inspect(measurements)}")
    217     Logger.info("Metadata: #{inspect(metadata)}")
    218   end
    219 end
    220 ```
    221 
    222 In Erlang:
    223 
    224 ```erlang
    225 -module(log_response_handler).
    226 
    227 -include_lib("kernel/include/logger.hrl").
    228 
    229 handle_event(Event, Measurements, Metadata, _Config) ->
    230   ?LOG_INFO("Event: ~p", [Event]),
    231   ?LOG_INFO("Measurements: ~p", [Measurements]),
    232   ?LOG_INFO("Metadata: ~p", [Metadata]).
    233 ```
    234 
    235 ## Installation
    236 
    237 Telemetry is available on [Hex](https://hex.pm/packages/telemetry). To install, just add it to
    238 your dependencies in `mix.exs`:
    239 
    240 ```elixir
    241 defp deps() do
    242   [
    243     {:telemetry, "~> 1.0"}
    244   ]
    245 end
    246 ```
    247 
    248 or `rebar.config`:
    249 
    250 ```erlang
    251 {deps, [{telemetry, "~> 1.0"}]}.
    252 ```
    253 
    254 ## Copyright and License
    255 
    256 Copyright (c) 2018 Chris McCord and Erlang Solutions.
    257 
    258 Telemetry's source code is released under the Apache License, Version 2.0.
    259 
    260 See the [LICENSE](LICENSE) and [NOTICE](NOTICE) files for more information.