{"id":13508390,"url":"https://github.com/pinterest/elixometer","last_synced_at":"2025-03-30T11:31:51.852Z","repository":{"id":36375822,"uuid":"40680676","full_name":"pinterest/elixometer","owner":"pinterest","description":"A light Elixir wrapper around exometer.","archived":false,"fork":false,"pushed_at":"2023-07-10T13:11:41.000Z","size":311,"stargazers_count":827,"open_issues_count":11,"forks_count":67,"subscribers_count":19,"default_branch":"master","last_synced_at":"2024-04-14T12:52:00.041Z","etag":null,"topics":["elixir","exometer","metrics"],"latest_commit_sha":null,"homepage":"https://hexdocs.pm/elixometer","language":"Elixir","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/pinterest.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}},"created_at":"2015-08-13T20:39:06.000Z","updated_at":"2024-04-11T20:42:55.000Z","dependencies_parsed_at":"2024-01-08T19:22:13.285Z","dependency_job_id":null,"html_url":"https://github.com/pinterest/elixometer","commit_stats":{"total_commits":210,"total_committers":31,"mean_commits":6.774193548387097,"dds":0.6952380952380952,"last_synced_commit":"d9d392cbfe2d39b6d205e651462c2498cab75a3f"},"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pinterest%2Felixometer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pinterest%2Felixometer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pinterest%2Felixometer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pinterest%2Felixometer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pinterest","download_url":"https://codeload.github.com/pinterest/elixometer/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246314011,"owners_count":20757450,"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","exometer","metrics"],"created_at":"2024-08-01T02:00:52.429Z","updated_at":"2025-03-30T11:31:46.841Z","avatar_url":"https://github.com/pinterest.png","language":"Elixir","funding_links":[],"categories":["Instrumenting / Monitoring","Elixir","Metrics"],"sub_categories":[],"readme":"Elixometer\n==========\n\nA light wrapper around [exometer](https://github.com/Feuerlabs/exometer).\n\nElixometer allows you to define metrics and subscribe them automatically\nto the default reporter for your environment.\n\n## Installation\nAdd the following to your dependencies in mix.exs:\n\n```elixir\n{:elixometer, \"~\u003e 1.5\"}\n```\n\nOr to track the master development branch:\n\n```elixir\n{:elixometer, github: \"pinterest/elixometer\"}\n```\n\nThen, add `:elixometer` to your applications. That's it!\n\n## Configuration\n\nIn one of your config files, set up an exometer reporter, and then register\nit to elixometer like this:\n\n```elixir\nconfig(:exometer_core, report: [reporters: [{:exometer_report_tty, []}]])\nconfig(:elixometer,\n  reporter: :exometer_report_tty,\n  env: Mix.env,\n  metric_prefix: \"myapp\")\n```\nMetrics are prepended with the `metric_prefix`, the type of metric and the environment name.\n\nThe optional `update_frequency` key of the :elixometer config controls the interval between reports. By default this is set to `1000` ms in the `dev` environment and `20` ms in the `test` environment.\n\nYou can use an environment variable to set the `env`.\n\n\n```elixir\nconfig :elixometer, env: {:system, \"ELIXOMETER_ENV\"}\n```\n\nSome reporters know how to handle multiple metrics reported at the same time. Or perhaps you want to write a custom reporter, and would like to receive all data points for a single metric all at once. \nThis can be achieved by adding the `report_bulk: true` option to the *reporter* configuration, and adding `bulk_subscribe: true` to the *elixometer* configuration. Like so:\n\n```elixir\nconfig :exometer_core,\n  report: [\n    reporters: [\n      {My.Custom.Reporter, [report_bulk: true]}\n    ]\n  ]\n\nconfig :elixometer,\n  # ...\n  bulk_subscribe: true\n```\n\nBy default, metrics are formatted using `Elixometer.Utils.format/2`.\nThis function takes care of composing metric names with prefix, environment and\nthe metric type (e.g. `myapp_prefix.dev.timers.request_time`).\n\nThis behaviour can be overridden with a custom formatter module (implementing the\n`Elixometer.Formatter` behaviour) by adding the following configuration entry:\n\n```elixir\nconfig :elixometer, Elixometer.Updater,\n  formatter: MyApp.Formatter\n```\n\nA formatting module implements the `Elixometer.Formatter` behaviour and implements\na single function, `format` as such:\n\n```elixir\ndefmodule MyApp.Formatter do\n  @behaviour Elixometer.Formatter\n\n  # If you prefer to hyphen-separate your strings, perhaps\n  def format(metric_type, name) do\n    String.split(\"#{metric_type}-#{name}\", \"-\")\n  end\nend\n```\n\nA formatting function can also be used as the configuration entry, provided it follows\nthe same signature as a formatting module:\n```elixir\nconfig :elixometer, Elixometer.Updater,\n  formatter: \u0026MyApp.Formatter.format/2\n```\n\nElixometer uses [`pobox`](https://github.com/ferd/pobox) to prevent overload.\nA maximum size of message buffer, defaulting to 1000, can be configured with:\n\n```elixir\nconfig :elixometer, Elixometer.Updater,\n  max_messages: 5000\n```\n\n### Excluding datapoints subscriptions\n\nBy default, adding a histogram adds for example 11 subscriptions (`[:n, :mean, :min, :max, :median, 50, 75, 90, 95, 99, 999]`).\nIf you would like to restrict which of these you care about, you can exclude some like so:\n\n```elixir\nconfig :elixometer, excluded_datapoints: [:median, 999]\n```\n\n## Metrics\n\nDefining metrics in elixometer is substantially easier than in exometer. Instead of defining and then updating a metric, just update it. Also, instead of providing a list of terms, a metric is named with a period separated bitstring. Presently, Elixometer supports timers, histograms, gauges, counters, and spirals.\n\nTimings may also be defined by annotating a function with a @timed annotation. This annotation takes a key argument, which tells elixometer what key to use. You  can specify `:auto` and a key will be generated from the module name and method name.\n\nUpdating a metric is similarly easy:\n\n```elixir\ndefmodule ParentModule.MetricsTest do\n  use Elixometer\n\n  # Updating a counter\n  def counter_test(thingie) do\n    update_counter(\"metrics_test.\\#{thingie}.count\", 1)\n  end\n\n  # Updating a spiral\n  def spiral_test(thingie) do\n    update_spiral(\"metrics_test.\\#{thingie}.qps\", 1)\n  end\n\n  # Timing a block of code in a function\n  def timer_test do\n    timed(\"metrics_test.timer_test.timings\") do\n      OtherModule.slow_method\n    end\n  end\n\n  # Timing a function. The metric name will be [:timed, :function]\n  @timed(key: \"timed.function\") # key will be: prefix.dev.timers.timed.function\n  def function_that_is_timed do\n    OtherModule.slow_method\n  end\n\n  # Timing a function with an auto generated key\n  # The key will be \"\u003cprefix\u003e.\u003cenv\u003e.timers.parent_module.metrics_test.another_timed_function\"\n  # If the env is prod, the environment is omitted from the key\n  @timed(key: :auto)\n  def another_timed_function do\n    OtherModule.slow_method\n  end\nend\n```\n\n## Additional Reporters\n\nBy default, Elixometer only requires the `exometer_core` package. However, some reporters (namely OpenTSDB and Statsd) are only available by installing the full `exometer` package. If you need the full package, all you need to do is update your `mix.exs` to include `exometer` as a dependency and start it as an application. For example:\n\n```elixir\ndef application do\n  [\n    applications: [:exometer,\n    ... other applications go here\n    ],\n    ...\n  ]\nend\n\ndefp deps do\n  [{:exometer_core, github: \"Feuerlabs/exometer_core\"}]\nend\n```\n\nIn case a reporter allows for extra configuration options on subscribe, you can configure them in your `elixometer` config like so:\n\n```elixir\nconfig(:elixometer,\n  ...\n  subscribe_options: [{:tag, :value1}])\n```\n\n## Custom Reporters\n\nThe documentation on custom reporters in `exometer` is fairly difficult to find, and isn't exactly correct. It is still quite useful though, and can be found [here](https://github.com/Feuerlabs/exometer_core/blob/master/doc/exometer_report.md).\n\nYour best bet is to define a module that uses the `:exometer_report` behaviour, and use `@impl` on the functions that you add to conform to that behaviour. \nThat will make sure that each function aligns with the behaviour, and that you haven't missed any required ones.\n\nThere is one function that is not included as part of the erlang behaviour, but that you may want, which is `exometer_report_bulk/3`. \n*If and only if* you have defined that function in your reporter *and* you passed `report_bulk: true` as an option to the reporter, it will pass a list of datapoint/value pairs to your `exometer_report_bulk/3`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpinterest%2Felixometer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpinterest%2Felixometer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpinterest%2Felixometer/lists"}