{"id":13508422,"url":"https://github.com/beam-telemetry/telemetry","last_synced_at":"2025-05-13T16:12:09.723Z","repository":{"id":37450946,"uuid":"143751561","full_name":"beam-telemetry/telemetry","owner":"beam-telemetry","description":"Dynamic dispatching library for metrics and instrumentations.","archived":false,"fork":false,"pushed_at":"2025-01-15T08:04:17.000Z","size":217,"stargazers_count":885,"open_issues_count":7,"forks_count":66,"subscribers_count":37,"default_branch":"main","last_synced_at":"2025-05-10T00:26:10.455Z","etag":null,"topics":["elixir","events","instrumentation","metrics"],"latest_commit_sha":null,"homepage":"https://hexdocs.pm/telemetry","language":"Erlang","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/beam-telemetry.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-08-06T15:58:01.000Z","updated_at":"2025-04-28T16:22:02.000Z","dependencies_parsed_at":"2024-05-01T16:20:00.537Z","dependency_job_id":"f808c661-5eb4-448b-9ec8-b54dd4ae1dbc","html_url":"https://github.com/beam-telemetry/telemetry","commit_stats":{"total_commits":141,"total_committers":35,"mean_commits":"4.0285714285714285","dds":0.5531914893617021,"last_synced_commit":"8d8af76720856bcf26641ee1307658ad8f25e466"},"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beam-telemetry%2Ftelemetry","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beam-telemetry%2Ftelemetry/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beam-telemetry%2Ftelemetry/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beam-telemetry%2Ftelemetry/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/beam-telemetry","download_url":"https://codeload.github.com/beam-telemetry/telemetry/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253850768,"owners_count":21973666,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["elixir","events","instrumentation","metrics"],"created_at":"2024-08-01T02:00:52.842Z","updated_at":"2025-05-13T16:12:04.708Z","avatar_url":"https://github.com/beam-telemetry.png","language":"Erlang","funding_links":[],"categories":["Instrumenting / Monitoring","Metrics"],"sub_categories":[],"readme":"# Telemetry\n\n[![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)\n\n[Documentation](https://hexdocs.pm/telemetry/)\n\nTelemetry is a lightweight library for dynamic dispatching of events, with a focus on\nmetrics and instrumentation. Any Erlang or Elixir library can use `telemetry` to emit\nevents. Application code and other libraries can then hook into those events and run\ncustom handlers.\n\n\u003e Note: this library is agnostic to tooling and therefore is not directly related to\n\u003e OpenTelemetry. For OpenTelemetry in the Erlang VM, see\n\u003e [opentelemetry-erlang](https://github.com/open-telemetry/opentelemetry-erlang), and check\n\u003e [opentelemetry_telemetry](https://github.com/open-telemetry/opentelemetry-erlang-contrib/tree/main/utilities/opentelemetry_telemetry)\n\u003e to connect both libraries.\n\n## Usage\n\nIn a nutshell, you register a custom module and function to be invoked for certain events,\nwhich are executed whenever there is such an event. The event name is a list of atoms. Each event is\ncomposed of a numeric value and can have metadata attached to it. Let's look at an example.\n\nImagine that you have a web application and you'd like to log latency and response status for each\nincoming request. With Telemetry, you can build a module which does exactly that whenever a response\nis sent. The first step is to execute a measurement.\n\nIn Elixir:\n\n```elixir\n:telemetry.execute(\n  [:web, :request, :done],\n  %{latency: latency},\n  %{request_path: path, status_code: status}\n)\n```\n\nIn Erlang:\n\n```erlang\ntelemetry:execute(\n  [web, request, done],\n  #{latency =\u003e Latency},\n  #{request_path =\u003e Path, status_code =\u003e Status}\n)\n```\n\nThen you can create a module to be invoked whenever the event happens.\n\nIn Elixir:\n\n```elixir\ndefmodule LogResponseHandler do\n  require Logger\n\n  def handle_event([:web, :request, :done], measurements, metadata, _config) do\n    Logger.info(\n      \"[#{metadata.request_path}] #{metadata.status_code} sent in #{measurements.latency}\"\n    )\n  end\nend\n```\n\nIn Erlang:\n\n```erlang\n-module(log_response_handler).\n\n-include_lib(\"kernel/include/logger.hrl\").\n\nhandle_event([web, request, done], #{latency := Latency}, #{request_path := Path,\n                                                            status_code := Status}, _Config) -\u003e\n  ?LOG_INFO(\"[~s] ~p sent in ~p\", [Path, Status, Latency]).\n\n```\n\n**Important note:**\n\nThe `handle_event` callback of each handler is invoked synchronously on each `telemetry:execute` call.\nTherefore, it is extremely important to avoid blocking operations. If you need to perform any action\nthat is not immediate, consider offloading the work to a separate process (or a pool of processes)\nby sending a message.\n\nFinally, all you need to do is to attach the module to the executed event.\n\nIn Elixir:\n\n```elixir\n:ok =\n  :telemetry.attach(\n    # unique handler id\n    \"log-response-handler\",\n    [:web, :request, :done],\n    \u0026LogResponseHandler.handle_event/4,\n    nil\n  )\n```\n\nIn Erlang:\n\n```erlang\nok = telemetry:attach(\n  %% unique handler id\n  \u003c\u003c\"log-response-handler\"\u003e\u003e,\n  [web, request, done],\n  fun log_response_handler:handle_event/4,\n  []\n)\n```\n\nYou might think that it isn't very useful, because you could just as well write a log statement\ninstead of calling `telemetry:execute/3` – and you would be right! But now imagine that each Elixir library\nwould publish its own set of events with information useful for introspection. Currently each library\nrolls their own instrumentation layer – Telemetry aims to provide a single interface for these use\ncases across the whole ecosystem.\n\n### Spans\n\nIn order to provide uniform events that capture the start and end of discrete events, it is recommended\nthat you use the `telemetry:span/3` call. This function will generate a start event and a stop or exception\nevent depending on whether the provided function executed successfully or raised an error. Under the hood,\nthe `telemetry:span/3` function leverages the `telemetry:execute/3` function, so all the same usage patterns\napply. If an exception does occur, an `EventPrefix ++ [exception]` event will be emitted and the caught error\nwill be re-raised.\n\nThe measurements for the `EventPrefix ++ [start]` event will contain a key called `system_time` which is\nderived by calling `erlang:system_time/0`. For `EventPrefix ++ [stop]` and `EventPrefix ++ [exception]`\nevents, the measurements will contain a key called `duration` and its value is derived by calling\n`erlang:monotonic_time() - StartMonotonicTime`. All events include a `monotonic_time` measurement too.\nAll of them represent time as native units.\n\nTo convert the duration from native units you can use:\n\n```elixir\nmilliseconds = System.convert_time_unit(duration, :native, :millisecond)\n```\n\nTo create span events you would do something like this:\n\nIn Elixir:\n\n```elixir\ndef process_message(message) do\n  start_metadata = %{message: message}\n\n  result =\n    :telemetry.span(\n      [:worker, :processing],\n      start_metadata,\n      fn -\u003e\n        result = ... # Process the message\n        {result, %{metadata: \"Information related to the processing of the message\"}}\n      end\n    )\nend\n```\n\nIn Erlang:\n\n```erlang\nprocess_message(Message) -\u003e\n  StartMetadata =  #{message =\u003e Message},\n  Result = telemetry:span(\n    [worker, processing],\n    StartMetadata,\n    fun() -\u003e\n      Result = % Process the message\n      {Result, #{metadata =\u003e \"Information related to the processing of the message\"}}\n    end\n  ).\n```\n\nTo then attach to the events that `telemetry:span/3` emits you would do the following:\n\nIn Elixir:\n\n```elixir\n:ok =\n  :telemetry.attach_many(\n    \"log-response-handler\",\n    [\n      [:worker, :processing, :start],\n      [:worker, :processing, :stop],\n      [:worker, :processing, :exception]\n    ],\n    \u0026LogResponseHandler.handle_event/4,\n    nil\n  )\n```\n\nIn Erlang:\n\n```erlang\nok = telemetry:attach_many(\n  \u003c\u003c\"log-response-handler\"\u003e\u003e,\n  [\n    [worker, processing, start],\n    [worker, processing, stop],\n    [worker, processing, exception]\n  ],\n  fun log_response_handler:handle_event/4,\n  []\n)\n```\n\nWith the following event handler module defined:\n\nIn Elixir:\n\n```elixir\ndefmodule LogResponseHandler do\n  require Logger\n\n  def handle_event(event, measurements, metadata, _config) do\n    Logger.info(\"Event: #{inspect(event)}\")\n    Logger.info(\"Measurements: #{inspect(measurements)}\")\n    Logger.info(\"Metadata: #{inspect(metadata)}\")\n  end\nend\n```\n\nIn Erlang:\n\n```erlang\n-module(log_response_handler).\n\n-include_lib(\"kernel/include/logger.hrl\").\n\nhandle_event(Event, Measurements, Metadata, _Config) -\u003e\n  ?LOG_INFO(\"Event: ~p\", [Event]),\n  ?LOG_INFO(\"Measurements: ~p\", [Measurements]),\n  ?LOG_INFO(\"Metadata: ~p\", [Metadata]).\n```\n\n## Installation\n\nTelemetry is available on [Hex](https://hex.pm/packages/telemetry). To install, just add it to\nyour dependencies in `mix.exs`:\n\n```elixir\ndefp deps() do\n  [\n    {:telemetry, \"~\u003e 1.0\"}\n  ]\nend\n```\n\nor `rebar.config`:\n\n```erlang\n{deps, [{telemetry, \"~\u003e 1.0\"}]}.\n```\n\n## Copyright and License\n\nCopyright (c) 2019 Erlang Ecosystem Foundation and Erlang Solutions.\n\nTelemetry's source code is released under the Apache License, Version 2.0.\n\nSee the [LICENSE](LICENSE) and [NOTICE](NOTICE) files for more information.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbeam-telemetry%2Ftelemetry","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbeam-telemetry%2Ftelemetry","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbeam-telemetry%2Ftelemetry/lists"}