{"id":13434964,"url":"https://github.com/Feuerlabs/exometer","last_synced_at":"2025-03-18T02:30:33.481Z","repository":{"id":9877940,"uuid":"11879291","full_name":"Feuerlabs/exometer","owner":"Feuerlabs","description":"Basic measurement objects and probe behavior","archived":false,"fork":false,"pushed_at":"2019-06-14T09:40:23.000Z","size":1698,"stargazers_count":527,"open_issues_count":16,"forks_count":105,"subscribers_count":46,"default_branch":"master","last_synced_at":"2025-03-14T22:04:16.712Z","etag":null,"topics":["erlang","exometer"],"latest_commit_sha":null,"homepage":null,"language":"Erlang","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Feuerlabs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-08-04T13:52:37.000Z","updated_at":"2025-01-23T23:59:31.000Z","dependencies_parsed_at":"2022-09-06T04:51:13.824Z","dependency_job_id":null,"html_url":"https://github.com/Feuerlabs/exometer","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Feuerlabs%2Fexometer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Feuerlabs%2Fexometer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Feuerlabs%2Fexometer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Feuerlabs%2Fexometer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Feuerlabs","download_url":"https://codeload.github.com/Feuerlabs/exometer/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244143847,"owners_count":20405286,"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":["erlang","exometer"],"created_at":"2024-07-31T03:00:28.888Z","updated_at":"2025-03-18T02:30:33.120Z","avatar_url":"https://github.com/Feuerlabs.png","language":"Erlang","readme":"\n\n# Exometer - Erlang instrumentation package #\n\nCopyright (c) 2014 Basho Technologies, Inc.  All Rights Reserved.\n\n__Version:__ Feb 1 2015 23:02:37\n\n__Authors:__ Ulf Wiger ([`ulf.wiger@feuerlabs.com`](mailto:ulf.wiger@feuerlabs.com)), Magnus Feuer ([`magnus.feuer@feuerlabs.com`](mailto:magnus.feuer@feuerlabs.com)).\n\n[![Build Status](https://travis-ci.org/Feuerlabs/exometer.png?branch=master)](https://travis-ci.org/Feuerlabs/exometer)\n\n__NOTE: Exometer has been split into [exometer_core](https://github.com/Feuerlabs/exometer_core), and exometer (as well as separate reporter applications). The latest monolithic version of Exometer is 1.1.__\n\nThe Exometer package allows for easy and efficient instrumentation of\nErlang code, allowing crucial data on system performance to be\nexported to a wide variety of monitoring systems.\n\nExometer comes with a set of pre-defined monitor components, and can\nbe expanded with custom components to handle new types of Metrics, as\nwell as integration with additional external systems such as\ndatabases, load balancers, etc.\n\nThis document gives a high level overview of the Exometer system. For\ndetails, please see the documentation for individual modules, starting\nwith `exometer`.\n\nNote the section on [Dependency Management](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#Dependency_Management) for how to deal with\noptional packages, both users and developers.\n\n\n### \u003ca name=\"Table_of_Content\"\u003eTable of Content\u003c/a\u003e ###\n\n\n1. [Concept and definitions](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#Concept_and_definitions)\n    1. [Metric](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#Metric)\n    2. [Data Point](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#Data_Point)\n    3. [Metric Type](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#Metric_Type)\n    4. [Entry Callback](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#Entry_Callback)\n    5. [Probe](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#Probe)\n    6. [Caching](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#Caching)\n    7. [Subscriptions and Reporters](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#Subscriptions_and_Reporters)\n2. [Built-in entries and probes](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#Built-in_entries_and_probes)\n    1. [counter (exometer native)](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#counter_(exometer_native))\n    2. [fast_counter (exometer native)](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#fast_counter_(exometer_native))\n    3. [gauge (exometer native)](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#gauge_(exometer_native))\n    4. [exometer_histogram (probe)](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#exometer_histogram_(probe))\n    5. [exometer_uniform (probe)](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#exometer_uniform_(probe))\n    6. [exometer_spiral (probe)](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#exometer_spiral_(probe))\n    7. [exometer_folsom [entry]](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#exometer_folsom_[entry])\n    8. [exometer_function [entry]](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#exometer_function_[entry])\n3. [Built in Reporters](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#Built_in_Reporters)\n    1. [exometer_report_graphite](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#exometer_report_graphite)\n    2. [exometer_report_opentsdb](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#exometer_report_opentsdb)\n    3. [exometer_report_amqp](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#exometer_report_amqp)\n    4. [exometer_report_snmp](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#exometer_report_snmp)\n4. [Instrumenting Erlang code](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#Instrumenting_Erlang_code)\n    1. [Exometer Start](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#Exometer_Start)\n    2. [Creating metrics](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#Creating_metrics)\n    3. [Deleting metrics](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#Deleting_metrics)\n    4. [Setting metric values](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#Setting_metric_values)\n    5. [Retrieving metric values](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#Retrieving_metric_values)\n    6. [Setting up subscriptions](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#Setting_up_subscriptions)\n    7. [Set metric options](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#Set_metric_options)\n5. [Configuring Exometer](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#Configuring_Exometer)\n    1. [Configuring type - entry maps](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#Configuring_type_-_entry_maps)\n    2. [Configuring statically defined entries](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#Configuring_statically_defined_entries)\n    3. [Configuring static subscriptions](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#Configuring_static_subscriptions)\n    4. [Configuring reporter plugins](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#Configuring_reporter_plugins)\n    5. [Configuring opentsdb reporter](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#Configuring_opentsdb_reporter)\n    6. [Configuring amqp reporter](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#Configuring_amqp_reporter)\n    7. [Configuring graphite reporter](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#Configuring_graphite_reporter)\n    8. [Configuring snmp reporter](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#Configuring_snmp_reporter)\n6. [Creating custom exometer entries](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#Creating_custom_exometer_entries)\n7. [Creating custom probes](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#Creating_custom_probes)\n8. [Creating custom reporter plugins](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#Creating_custom_reporter_plugins)\n9. [Dependency management](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#Dependency_management)\n\n\n### \u003ca name=\"Concepts_and_Definitions\"\u003eConcepts and Definitions\u003c/a\u003e ###\n\nExometer introduces a number of concepts and definitions used\nthroughout the documentation and the code.\n\n![Overview](/doc/exometer_overview.png?raw=true)\n\n\n#### \u003ca name=\"Metric\"\u003eMetric\u003c/a\u003e ####\n\nA metric is a specific measurement sampled inside an Erlang system and\nthen reported to the Exometer system. An example metric would be\n\"transactions_per_second\", or \"memory_usage\".\n\nMetrics are identified by a list of terms, such as given below:\n\n`[ xml_front_end, parser, file_size ]`\n\nA metric is created through a call by the code to be instrumented to\n`exometer:new()`. Once created, the metric can be updated through\n`exometer:update()`, or on its own initiative through the\n`exometer_probe:sample` behavior implementation.\n\n\n#### \u003ca name=\"Data_Point\"\u003eData Point\u003c/a\u003e ####\n\nEach metric can consist of multiple data points, where each point has\na specific value.\n\nA typical example of data points would be a\n`transactions_per_second` (tps) metric, usually stored as a\nhistogram covering the last couple of minutes of tps samples. Such a\nhistogram would host multiple values, such as `min`, `max`,\n`median`, `mean`, `50_percentile`, `75_percentile`,\netc.\n\nIt is up to the type of the metric, and the data probe backing that\ntype (see below), to specify which data points are available under the\ngiven metric.\n\n\n#### \u003ca name=\"Metric_Type\"\u003eMetric Type\u003c/a\u003e ####\n\nThe type of a metric, specified when the metric is created through\n`exometer:new()`, determines which `exometer_entry`\ncallback to use.\n\nThe link between the type and the entry to use is configured\nthrough the `exometer_admin` module, and its associated exometer\ndefaults configuration data.\n\nThe metric type, in other words, is mainly used to map a metric to a\nconfigurable `exometer_entry` callback, but it can also be referenced\nin queries using `exometer:select/1`. An entry callback can also support\nmultiple types (the type is provided as an argument in the callback functions).\n\nExometer provides default mappings for a number of metric types. It is\npossible to select different callbacks for each metric instance, as well\nas modify metrics using callback-specific options. Please see\n[Configuring type - entry maps](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#Configuring_type_-_entry_maps) for details on how to do this.\n\n\n#### \u003ca name=\"Entry_Callback\"\u003eEntry Callback\u003c/a\u003e ####\n\nAn exometer entry callback will receive values reported to a metric through the\n`exometer:update()` call and compile it into one or more data points.\nThe entry callback can either be a counter (implemented natively\nin `exometer`), or a more complex statistical analysis such\nas a uniform distribution or a regular histogram.\n\nThe various outputs from these entries are reported as data points\nunder the given metric.\n\nAn entry can also interface external analytics packages.\n`exometer_folsom`, for example, integrates with the\n`folsom_metrics` package found at [`https://github.com/boundary/folsom`](https://github.com/boundary/folsom).\n\n\n#### \u003ca name=\"Probe\"\u003eProbe\u003c/a\u003e ####\n\nProbes are a further specialization of exometer entries that run in\ntheir own Erlang processes and have their own state (like a\ngen_server). A probe is implemented through the `exometer_probe`\nbehavior.\n\nA probe can be used if independent monitoring is needed of,\nfor example, `/proc` trees, network interfaces, and other subsystems\nthat need periodic sampling. In these cases, the\n`exometer_probe:probe_sample()` call is invoked regularly by exometer,\nin the probe's own process, in order to extract data from\nthe given subsystem and add it to the metric's data points.\n\n\n#### \u003ca name=\"Caching\"\u003eCaching\u003c/a\u003e ####\n\nMetric and data point values are read with the `exometer:get_value()`\nfunction. In the case of counters, this operation is very fast. With probes,\nthe call results in a synchronous dialog with the probe process, and the\ncost of serving the request depends on the probe implementation and the\nnature of the metric being served.\n\nIf the cost of reading the value is so high that calling the function often\nwould result in prohibitive load, it is possible to cache the value. This is\ndone either explicitly from the probe itself (by calling\n`exometer_cache:write()`), or by specifying the option `{cache, Lifetime}`\nfor the entry. If an entry has a non-zero cache lifetime specified, the\n`get_value()` call will try fetching the cached value before calling the\nactual entry and automatically caching the result.\n\nNote that if `{cache, Lifetime}` is not specified, `exometer:get_value()`\nwill neither read nor write to the cache. It is possible for the probe\nto periodically cache a value regardless of how the cache lifetime is set,\nand the probe may also explicitly read from the cache if it isn't done\nautomatically.\n\n\n#### \u003ca name=\"Subscriptions_and_Reporters\"\u003eSubscriptions and Reporters\u003c/a\u003e ####\n\nThe subscription concept, managed by `exometer_report` allows metrics\nand their data points to be sampled at given intervals and delivered\nto one or more recipients, which can be either an arbitrary process\nor a Reporter plugin.\n\nEach subscription ties a specific metric-datapoint pair to a reporter\nand an interval (given in milliseconds). The reporter system will, at\nthe given interval, send the current value of the data point to the\nsubscribing reporter. The subscription, with all its parameters,\nis setup through a call to `exometer_report:subscribe()`.\n\nIn the case of processes, subscribed-to values will be delivered as a\nmessage. Modules, which implement the `exometer_report` callback\nbehavior, will receive the plugins as a callbacks within the\n`exometer_report` process.\n\nSubscriptions can either be setup at runtime, through\n`exometer_report:subscribe()` calls, or statically through the\n`exometer_report` configuration data.\n\n\n### \u003ca name=\"Built-in_entries_and_probes\"\u003eBuilt-in entries and probes\u003c/a\u003e ###\n\n\nThere are a number of built-in entries and probes shipped\nwith the Exometer package, as described below:\n\n\n#### \u003ca name=\"counter_(exometer_native)\"\u003ecounter (exometer native)\u003c/a\u003e ####\n\n\nThe counter is implemented directly in `exometer` to provide simple\ncounters.  A call to `exometer:update()` will add the provided value\nto the counter.\n\nThe counter can be reset to zero through `exometer:reset()`.\n\nThe available data points under a metric using the counter entry\nare `value` and `ms_since_reset`.\n\n\n#### \u003ca name=\"fast_counter_(exometer_native)\"\u003efast_counter (exometer native)\u003c/a\u003e ####\n\nA fast counter implements the counter functionality, through the\n`trace_info` system, yielding a speed increase of about 3.5 in\ncomparison to the regular counter.\n\nThe tradeoff is that running tracing and/or debugging may interfere\nwith the counter functionality.\n\nA call to `exometer:update()` will add the provided value to the\ncounter.\n\nThe counter can be reset to zero through `exometer:reset()`.\n\nThe available data points under a metric using the fast_counter\nentry are `value` and `ms_since_reset`.\n\n\n#### \u003ca name=\"gauge_(exometer_native)\"\u003egauge (exometer native)\u003c/a\u003e ####\n\nThe gauge is implemented directly in `exometer` to provide simple\ngauges.  A call to `exometer:update()` will set the gauge's value\nto the provided value. That is, the value of the gauge entry is\nalways the most recently provided value.\n\nThe gauge can be reset to zero through `exometer:reset()`.\n\nThe available data points under a metric using the gauge entry\nare `value` and `ms_since_reset`.\n\n\n#### \u003ca name=\"histogram_(probe)\"\u003ehistogram (probe)\u003c/a\u003e ####\n\nThe histogram probe stores a given number of updates, provided through\n`exometer:update()`, in a histogram. The histogram maintains a log\nderived from all values received during a configurable time span and\nprovides min, max, median, mean, and percentile analysis data points\nfor the stored data.\n\nExometer supports a number of different histogram implementations, each\nwith different performance and accuracy trade-offs. \n\nIn order to save memory, the histogram is divided into equal-sized\ntime slots, where each slot spans a settable interval. All values\nreceived during a time slot will be averaged into a single value to be\nstored in the histogram once the time slot expires. The averaging\nfunction (which can be replaced by the caller), allows for\nhigh-frequency update metrics to have their resolution traded against\nresource consumption.\n\n\n#### \u003ca name=\"exometer_uniform_(probe)\"\u003eexometer_uniform (probe)\u003c/a\u003e ####\n\nThe uniform probe provides a uniform sample over a pool of values\nprovided through `exometer:update()`. When the pool reaches its configurable\nmax size, existing values will be replaced at random to make space for\nnew values. Much like `exometer_histogram`, the uniform probe\nprovides min, max, median, mean, and percentile analysis data points\nfor the stored data.\n\n\n#### \u003ca name=\"exometer_spiral_(probe)\"\u003eexometer_spiral (probe)\u003c/a\u003e ####\n\nThe spiral probe maintains the total sum of all values stored in its\nhistogram. The histogram has a configurable time span, all values\nprovided to the probe, through `exometer:update()`, within that time\nspan will be summed up and reported. If, for example, the histogram\ncovers 60 seconds, the spiral probe will report the sum of all\nvalues reported during the last minute.\n\nThe grand total of all values received during the lifetime of the\nprobe is also available.\n\n\n#### \u003ca name=\"exometer_folsom_[entry]\"\u003eexometer_folsom [entry]\u003c/a\u003e ####\n\n`exometer_folsom` is an entry behavior which implements most metric types\nsupported by the [folsom](https://github.com/boundary/folsom)\nmetrics package: Specifically, the metric types `counter`, `spiral`,\n`histogram`, `meter`, `meter_reader`, `gauge`, `duration` and `history`.\n\nThe folsom entry integrates with the folsom metrics package provided\nby the boundary repo at github. Updated values sent to the folsom entry\ncan be forwarded to folsom's counter, histogram, duration, meter,\nand spiral.\n\nFolsom integration is provided as a backup. New code using Exometer\nshould use the native probes that duplicate folsom.\n\n\n#### \u003ca name=\"exometer_function_[entry]\"\u003eexometer_function [entry]\u003c/a\u003e ####\n\nThe function entry allows for an existing erlang function to be wrapped\nas an exometer entry. The [`exometer_function`](https://github.com/Feuerlabs/exometer_core/blob/master/doc/exometer_function.md) module supports a number\nof options for passing arguments and matching out data points from the\nresult.\n\nThe function entry provides an easy way of integrating an external\nsystem without having to write a complete entry.\n\n\n### \u003ca name=\"Built_in_Reporters\"\u003eBuilt in Reporters\u003c/a\u003e ###\n\nExometer ships with some built-in reporters which can be used to forward updated\nmetrics and their data points to external systems. They can also\nserve as templates for custom-developed reporters.\n\n\n#### \u003ca name=\"exometer_report_graphite\"\u003eexometer_report_graphite\u003c/a\u003e ####\n\nThe graphite reporter uses the TCP/IP protocol to forward\nsubscribed-to metrics and data points to a graphite server, such as\nthe one provided by [`http://hostedgraphite.com`](http://hostedgraphite.com). When the graphite\nreporter receives a metric-datapoint value (subscribed to through\n`exometer_report:subscriber()`), the reporter will immediately\nforward the key-value pair to the graphite server.\n\n\n#### \u003ca name=\"exometer_report_opentsdb\"\u003eexometer_report_opentsdb\u003c/a\u003e ####\n\nThe OpenTSDB reporter sends metrics to an OpenTSDB server using\nthe telnet API. All subscribed-to metric-datapoint values received\nby the reporter are immediately forwarded to OpenTSDB.\n\nIf the OpenTSDB connection is lost, the reporter will attempt to reconnect to it\nat a configurable interval.\n\nThe data sent to OpenTSDB will be formatted as follows:\n\n```\nput metric timestamp value host=host type=datapoint\n```\n\nWhere the value for the host tag will be the configured host in the reporter\nconfiguration (defaults to the value returned by `netadm:localhost`), and\ndatapoint tags as specified by the subscriber.\n\nPlease see [Configuring opentsdb reporter](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#Configuring_opentsdb_reporter) for details on the\napplication environment parameters listed above.\n\n\n#### \u003ca name=\"exometer_report_amqp\"\u003eexometer_report_amqp\u003c/a\u003e ####\n\nThe AMQP reporter sends metrics to an AMQP broker as a json-encoded payload. All\nsubscribed-to metric-datapoint values received by the reporter are forwarded to AMQP.\n\nIf the AMQP connection is lost, the reporter will attempt to reconnect to it\nat a configurable interval.\n\nThe data sent to AMQP will be formatted as follows:\n\n```\n{\n  \"type\":\"exometer_metric\",\n  \"body\":\n    {\"name\":\"messages_per_second\",\n     \"value\":0,\"timestamp\":1414006826,\n     \"host\":\"testhost\",\n     \"instance\":\"max\"}\n}\n```\n\nWhere the value for the host tag will be the configured host in the reporter\nconfiguration (defaults to the value returned by `netadm:localhost`), the\ninstance tag represents the datapoint for the metric.\n\nPlease see [Configuring amqp reporter](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#Configuring_amqp_reporter) for details on the\napplication environment parameters listed above.\n\n\n#### \u003ca name=\"exometer_report_snmp\"\u003eexometer_report_snmp\u003c/a\u003e ####\n\nThe SNMP reporter enables the export of metrics and their datapoints to SNMP managers.\nThe export needs to be enabled for each metric through their options.\nMoreover, SNMP notifications can be created using the options to send periodic reports\non datapoints to SNMP managers. All SNMP protocol handling is done by the snmp application\nshipped with Erlang/OTP. Thus, the snmp application needs to be started and\nthe local SNMP master agent needs to be configured correctly for SNMP export to work\nproperly.\n\nTo configure SNMP export for a single metric use these options:\n\n+ `{snmp, disabled}` (default)\u003cbr /\u003eDisables SNMP export for the metric. Same as not specifying the option at all.\n\n+ `{snmp, []}`\u003cbr /\u003eEnables SNMP export for the metric. No subscriptions are setup.\n\n+ `{snmp, [{Datapint, Interval}]}`\u003cbr /\u003eEnables SNMP export for the metric.\u003cbr /\u003eSubscriptions are setup for the given Datapoint/Interval pairs.\u003cbr /\u003eEach subscription report will be forwarded to SNMP mangers as notifications.\n\n+ `{snmp, [{Datapint, Interval, Extra}]}`\u003cbr /\u003eSame as above, but using an addition extra identification for the subscriptions.\u003cbr /\u003eAllow the creation ofmultiple subscriptions for a single datapoint.\n\nPlease see [Configuring snmp reporter](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#Configuring_snmp_reporter) for details on how to configure the\nSNMP reporter.\n\n\n### \u003ca name=\"Instrumenting_Erlang_code\"\u003eInstrumenting Erlang code\u003c/a\u003e ###\n\nThe code using Exometer needs to be instrumented in order to setup and\nuse metrics reporting.\n\n\n#### \u003ca name=\"Exometer_Start\"\u003eExometer Start\u003c/a\u003e ####\n\nThe system using Exometer must start the `exometer` application prior to using it:\n\n```erlang\n\napplication:start(lager),\napplication:start(exometer).\n```\n\nNote that dependent applications need to be started first. On newer OTP versions\n(R16B or later), you can use `application:ensure_all_started(exometer)`.\n\nFor testing, you can also use [`exometer:start/0`](https://github.com/Feuerlabs/exometer_core/blob/master/doc/exometer.md#start-0).\n\nIf you make use of e.g. folsom metrics, you also need to start `folsom`. Exometer\nwill not do that automatically, nor does it contain an application dependency for it.\n\nSee [Configuring Exometer](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#Configuring_Exometer) for details on configuration data\nformat.\n\n\n#### \u003ca name=\"Creating_metrics\"\u003eCreating metrics\u003c/a\u003e ####\n\nA metric, can be created through a call to\n\n```erlang\n\nexometer:new(Name, Type)\n```\n\n`Name` is a list of atoms, uniquely identifying the metric created.\nThe type of the metric, specified by `Type` will be mapped\nto an exometer entry through the table maintained by\n`exometer_admin` Please see the [Configuring type - entry\nmaps](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#Configuring_type_-_entry_maps) for details.\n\nThe resolved entry to use will determine the data points available\nunder the given metric.\n\n\n#### \u003ca name=\"Deleting_metrics\"\u003eDeleting metrics\u003c/a\u003e ####\n\nA metric previously created with `exometer:new()` can be deleted by\n`exometer:delete()`.\n\nAll subscriptions to the deleted metrics will be cancelled.\n\n\n#### \u003ca name=\"Setting_metric_values\"\u003eSetting metric values\u003c/a\u003e ####\n\nA created metric can have its value updated through the\n`exometer:update()` function:\n\n```erlang\n\nexometer:update(Name, Value)\n```\n\nThe `Name` parameter is the same atom list provided to a previous\n`exometer:new()` call. The `Value` is an arbitrarty element that is\nforwarded to the `exometer:update()` function of the entry/probe that the\nmetric is mapped to.\n\nThe receiving entry/probe will process the provided value and modify\nits data points accordingly.\n\n\n#### \u003ca name=\"Retrieving_metric_values\"\u003eRetrieving metric values\u003c/a\u003e ####\n\nExometer-using code can at any time retrieve the data point values\nassociated with a previously created metric. In order to find out which\ndata points are available for a metric, the following call can be used:\n\n```erlang\n\nexometer:info(Name, datapoints)\n```\n\nThe `Name` parameter is the same atom list provided to a previous\n`exometer:new()` call. The call will return a list of data point\natoms that can then be provided to `exometer:get_value()` to\nretrieve their actual value:\n\n```erlang\n\nexometer:get_value(Name, DataPoint)\n```\n\nThe `Name` paramer identifies the metric, and `DataPoints`\nidentifies the data points (returned from the previous `info()` call)\nto retrieve the value for.\n\nIf no DataPoints are provided, the values of a default list of data points,\ndetermined by the backing entry / probe, will be returned.\n\n\n#### \u003ca name=\"Setting_up_subscriptions\"\u003eSetting up subscriptions\u003c/a\u003e ####\n\nA subscription can either be statically configured, or dynamically\nsetup from within the code using Exometer. For details on statically\nconfigured subscriptions, please see [Configuring static subscriptions](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#Configuring_static_subscriptions).\n\nA dynamic subscription can be setup with the following call:\n\n```erlang\n\nexometer_report:subscribe(Recipient, Metric, DataPoint, Inteval)\n```\n\n`Recipient` is the name of a reporter.\n\n\n#### \u003ca name=\"Set_metric_options\"\u003eSet metric options\u003c/a\u003e ####\n\n\nEach created metric can have options setup for it through the following call:\n\n```erlang\n\nexometer:setopts(Name, Options)\n```\n\nThe `Name` paramer identifies the metric to set the options for, and\nOptions is a proplist (`[{ Key, Value },...]`) with the options to be\nset.\n\nExometer looks up the the backing entry that hosts the metric with the given Name, and will\ninvoke the entry\\'s `setopts/4` function to set the actual options. Please see the\n`setopts/4` function for the various entries for details.\n\n\n### \u003ca name=\"Configuring_Exometer\"\u003eConfiguring Exometer\u003c/a\u003e ###\n\nExometer defaults can be changed either through OTP application environment\nvariables or through the use of Basho's `cuttlefish`\n([`https://github.com/basho/cuttlefish`](https://github.com/basho/cuttlefish)).\n\n\n#### \u003ca name=\"Configuring_type_-_entry_maps\"\u003eConfiguring type - entry maps\u003c/a\u003e ####\n\nThe dynamic method of configuring defaults for `exometer` entries is:\n\n```erlang\n\nexometer_admin:set_default(NamePattern, Type, Default)\n```\n\nWhere `NamePattern` is a list of terms describing what is essentially\na name prefix with optional wildcards (`'_'`). A pattern that\nmatches any legal name is `['_']`.\n\n`Type` is an atom defining a type of metric. The types already known to\n`exometer`, `counter`, `fast_counter`, `ticker`, `uniform`, `histogram`,\n`spiral`, `netlink`, and `probe` may be redefined, but other types can be\ndescribed as well.\n\n`Default` is either an `#exometer_entry{}` record (unlikely), or a list of\n`{Key, Value}` options, where the keys correspond to `#exometer_entry` record\nattribute names. The following attributes make sense to preset:\n\n```erlang\n\n{module, atom()}              % the callback module\n{status, enabled | disabled}  % operational status of the entry\n{cache, non_neg_integer()}    % cache lifetime (ms)\n{options, [{atom(), any()}]}  % entry-specific options\n```\n\nBelow is an example, from `exometer/priv/app.config`:\n\n```erlang\n\n{exometer, [\n    {defaults, [\n        {['_'], function , [{module, exometer_function}]},\n        {['_'], counter  , [{module, exometer}]},\n        {['_'], histogram, [{module, exometer_histogram}]},\n        {['_'], spiral   , [{module, exometer_spiral}]},\n        {['_'], duration , [{module, exometer_folsom}]},\n        {['_'], meter    , [{module, exometer_folsom}]},\n        {['_'], gauge    , [{module, exometer_folsom}]}\n    ]}\n]}\n```\n\nIn systems that use CuttleFish, the file `exometer/priv/exometer.schema`\ncontains a schema for default settings. The setup corresponding to the above\ndefaults would be as follows:\n\n```ini\n\nexometer.template.function.module  = exometer_function\nexometer.template.counter.module   = exometer\nexometer.template.histogram.module = exometer_histogram\nexometer.template.spiral.module    = exometer_spiral\nexometer.template.duration.module  = exometer_folsom\nexometer.template.meter.module     = exometer_folsom\nexometer.template.gauge.module     = exometer_folsom\n```\n\n\n#### \u003ca name=\"Configuring_statically_defined_entries\"\u003eConfiguring statically defined entries\u003c/a\u003e ####\n\nUsing the `exometer` environment variable `predefined`, entries can be added\nat application startup. The variable should have one of the following values:\n\n* `{script, File}` - `File` will be processed using `file:script/2`. The return\n  value (the result of the last expression in the script) should be a list of`{Name, Type, Options}` tuples.\n\n* `{apply, M, F, A}` - The result of `apply(M, F, A)` should be `{ok, L}` where`L` is a list of `{Name, Type, Options}` tuples.\n\n* `L`, where L is a list of `{Name, Type, Options}` tuples or extended\ninstructions (see below).\n\nThe list of instructions may include:\n\n* `{delete, Name}` - deletes `Name` from the exometer registry.\n\n* `{select_delete, Pattern}` - applies a select pattern and\ndeletes all matching entries.\n\n* `{re_register, {Name, Type, Options}}` - redefines an entry if present,\notherwise creates it.\n\nExometer will also scan all loaded applications for the environment\nvariables `exometer_defaults` and `exometer_predefined`, and process\nas above. If an application is loaded and started after exometer has started,\nit may call the function `exometer:register_application()` or\n`exometer:register_application(App)`. This function will do nothing if\nexometer isn't already running, and otherwise process the `exometer_defaults`\nand `exometer_predefined` variables as above. The function can also be\ncalled during upgrade, as it will re-apply the settings each time.\n\n\n#### \u003ca name=\"Configuring_static_subscriptions\"\u003eConfiguring static subscriptions\u003c/a\u003e ####\n\n\nStatic subscriptions, which are automatically setup at exometer\nstartup without having to invoke `exometer_report:subscribe()`, are\nconfigured through the report sub section under exometer.\n\nBelow is an example, from `exometer/priv/app.config`:\n\n```erlang\n\n{exometer, [\n    {report, [\n        {subscribers, [\n            {exometer_report_collectd, [db, cache, hits], mean, 2000, true},\n            {exometer_report_collectd, [db, cache, hits], max, 5000, false}\n        ]}\n    ]}\n]}\n```\n\nThe `report` section configures static subscriptions and reporter\nplugins. See [Configuring reporter plugins](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#Configuring_reporter_plugins) for details on\nhow to configure individual plugins.\n\nThe `subscribers` sub-section contains all static subscriptions to be\nsetup att exometer applications start. Each tuple in the prop list\nshould be of one of the following formats:\n\n* `{Reporter, Metric, DataPoint, Interval}`\n\n* `{Reporter, Metric, DataPoint, Interval, RetryFailedMetrics}`\n\n* `{Reporter, Metric, DataPoint, Interval, RetryFailedMetrics, Extra}`\n\n* `{apply, {M, F, A}}`\n\n* `{select, {MatchPattern, DataPoint, Interval [, Retry [, Extra] ]}}`\n\nIn the case of `{apply, M, F, A}`, the result of `apply(M, F, A)` must\nbe a list of `subscribers` tuples.\n\nIn the case of `{select, Expr}`, a list of metrics is fetched using\n`exometer:select(MatchPattern)`, where the result must be on the form\n`{Key, Type, Status}` (i.e. what corresponds to `'$_'`).\nThe rest of the items will be applied to each of the matching entries.\n\nThe meaning of the above tuple elements is:\n\n+ `Reporter :: module()`\u003cbr /\u003eSpecifies the reporter plugin module, such as`exometer_report_collectd` that is to receive updated metric's data\npoints.\n\n+ `Metric :: [atoms()]`\u003cbr /\u003eSpecifies the path to a metric previously created with an`exometer:new()` call.\n\n+ `DataPoint` ::  atom() | [atom()]'\u003cbr /\u003eSpecifies the data point within the given metric to send to the\n    receiver. The data point must match one of the data points returned by`exometer:info(Name, datapoints)` for the given metrics name.\n\n+ `Interval` :: integer()' (milliseconds)\u003cbr /\u003eSpecifies the interval, in milliseconds, between each update of the\ngiven metric's data point. At the given interval, the data point will\nbe samples, and the result will be sent to the receiver.\n\n+ `RetryFailedMetrics :: boolean()`\u003cbr /\u003eSpecifies if the metric should be continued to be reported\n    even if it is not found during a reporting cycle. This would be\n    the case if a metric is not created by the time it is reported for\n    the first time. If the metric will be created at a later time,\n    this value should be set to true. Set this value to false if all\n    attempts to report the metric should stop if when is not found.\n    The default value is `true`.\n\n+ `Extra :: any()`\u003cbr /\u003eProvides a means to pass along extra information for a given\n   subscription. An example is the `syntax` option for the SNMP reporter,\n   in which case `Extra` needs to be a property list.\n\nExample configuration in sys.config, using the `{select, Expr}` pattern:\n\n```erlang\n\n[\n {exometer, [\n             {predefined,\n              [{[a,1], counter, []},\n               {[a,2], counter, []},\n               {[b,1], counter, []},\n               {[c,1], counter, []}]},\n             {report,\n              [\n               {reporters,\n                [{exometer_report_tty, []}]},\n               {subscribers,\n                [{select, {[{ {[a,'_'],'_','_'}, [], ['$_']}],\n                           exometer_report_tty, value, 1000}}]}\n              ]}\n            ]}\n].\n\n```\n\nThis will activate a subscription on `[a,1]` and `[a,2]` in the\n`exometer_report_tty` reporter, firing once per second.\n\n\n#### \u003ca name=\"Configuring_reporter_plugins\"\u003eConfiguring reporter plugins\u003c/a\u003e ####\n\n\nThe various reporter plugins to be loaded by exometer are configured\nin the `report` section under `reporters`\n\nEach reporter has an entry named after its module, and the content of\nthat entry is dependent on the reporter itself. The following chapters\nspecifies the configuration parameters for the reporters shipped with\nexometer.\n\n\n#### \u003ca name=\"Configuring_opentsdb_reporter\"\u003eConfiguring opentsdb reporter\u003c/a\u003e ####\n\n\nBelow is an example of the opentsdb reporter application environment, with\nits correct location in the hierarchy:\n\n```erlang\n\n{exometer, [\n    {report, [\n        {reporters, [\n            {exometer_report_opentsdb, [\n                {reconnect_interval, 10},\n                {connect_timeout, 8000},\n                {hostname, \"testhost\"},\n                {host, {\"127.0.0.1\", 4242}}\n            ]}\n        ]}\n    ]}\n]}\n```\n\nThe following attributes are available for configuration:\n\n+ `reconnect_interval` (seconds - default: 30)\u003cbr /\u003eSpecifies the duration between each reconnect attempt to an opentsdb\nserver that is not available. Should the server either be unavailable\nat exometer startup, or become unavailable during exometer's\noperation, exometer will attempt to reconnect at the given number of\nseconds.\n\n+ `connect_timeout` (milliseconds - default: 5000)\u003cbr /\u003eSpecifies how long the opentsdb reporter plugin shall wait for a\nsocket connection to complete before timing out. A timed out\nconnection attempt will be retried after the reconnect interval has\npassed see item 1 above).\n\n+ `hostname` (string - default: `net_adm:localhost()`)\u003cbr /\u003eSpecifies the host name to use for the host tag in the OpenTSDB tags.\n    Please see [Configuring opentsdb reporter](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#Configuring_opentsdb_reporter) for details.\n\n+ `host` (ip - default: {\"127.0.0.1\", 4242})\u003cbr /\u003eSpecifies the host and port to connect to OpenTSDB.\n\n\n#### \u003ca name=\"Configuring_amqp_reporter\"\u003eConfiguring amqp reporter\u003c/a\u003e ####\n\n\nBelow is an example of the amqp reporter application environment, with\nits correct location in the hierarchy:\n\n```erlang\n\n{exometer, [\n    {report, [\n        {reporters, [\n            {exometer_report_amqp, [\n                {reconnect_interval, 10},\n                {hostname, \"testhost\"},\n                {amqp_url, \"amqp://user:pass@host:5672/%2f\"},\n\t\t{exchange, \"metrics\"},\n\t\t{routing_key, \"metrics\"},\n\t\t{buffer_size, 0}\n            ]}\n        ]}\n    ]}\n]}\n```\n\nThe following attributes are available for configuration:\n\n+ `reconnect_interval` (seconds - default: 30)\u003cbr /\u003eSpecifies the duration between each reconnect attempt to an amqp\nbroker that is not available. Should the server either be unavailable\nat exometer startup, or become unavailable during exometer's\noperation, exometer will attempt to reconnect at the given number of\nseconds.\n\n+ `hostname` (string - default: `net_adm:localhost()`)\u003cbr /\u003eSpecifies the host name to use for the host property in the JSON payload.\n    Please see [Configuring amqp reporter](https://github.com/Feuerlabs/exometer/blob/master/doc/README.md#Configuring_amqp_reporter) for details.\n\n+ `amqp_url` (string - default: `amqp://guest:guest@localhost:5672/%2f`)\u003cbr /\u003eSpecifies the amqp url to connect to.\n\n+ `exchange` (string - default: `exometer`)\u003cbr /\u003eSpecifies the exchange to publish messages to.\n\n+ `routing_key` (string - default: `exometer`)\u003cbr /\u003eSpecifies the routing key to use when publishing messages.\n\n+ `buffer_size` (integer - default: `0`)\u003cbr /\u003eSpecifies the size in bytes of payload to buffer before sending to AMQP.\n\n\n#### \u003ca name=\"Configuring_graphite_reporter\"\u003eConfiguring graphite reporter\u003c/a\u003e ####\n\n\nBelow is an example of the a graphite reporter application environment, with\nits correct location in the hierarchy:\n\n```erlang\n\n{exometer, [\n    {report, [\n        {reporters, [\n            {exometer_report_graphite, [\n                {connect_timeout, 5000},\n                {prefix, \"web_stats\"},\n                {host, \"carbon.hostedgraphite.com\"},\n                {port, 2003},\n                {api_key, \"267d121c-8387-459a-9326-000000000000\"}\n            ]}\n        ]}\n    ]}\n]}\n```\n\nThe following attributes are available for configuration:\n\n+ `connect_timeout` (milliseconds - default: 5000)\u003cbr /\u003eSpecifies how long the graphie reporter plugin shall wait for a tcp\nconnection to complete before timing out. A timed out connection will\nnot be reconnected to automatically. (To be fixed.)\n\n+ `prefix` (string - default: \"\")\u003cbr /\u003eSpecifies an optional prefix to prepend all metric names with before\nthey are sent to the graphite server.\n\n+ `host` (string - default: \"carbon.hostedgraphite.com\")\u003cbr /\u003eSpecifies the name (or IP address) of the graphite server to report to.\n\n+ `port` (integer - default: 2003)\u003cbr /\u003eSpecifies the TCP port on the given graphite server to connect to.\n\n+ `api_key` (string - default: n/a)\u003cbr /\u003eSpecifies the api key to use when reporting to a hosted graphite server.\n\nIf `prefix` is not specified, but `api_key` is, each metrics will be reported as `ApiKey.Metric`.\n\nIf `prefix` is specified, but `api_key` is not, each metrics will be reported as `Prefix.Metric`.\n\nif neither `prefix` or `api_key` is specified, each metric will be reported simply as `Metric`.\n\n\n#### \u003ca name=\"Configuring_snmp_reporter\"\u003eConfiguring snmp reporter\u003c/a\u003e ####\n\n\nBelow is an example of the a snmp reporter application environment, with\nits correct location in the hierarchy:\n\n```erlang\n\n{exometer, [\n    {report, [\n        {reporters, [\n            {exometer_report_snmp, [\n                {mib_template, \"priv/MYORG-EXOMETER-METRICS.mib\"},\n                {mib_dir, \"/tmp/exometer\"}\n            ]}\n        ]}\n    ]}\n]}\n```\n\nThe following attributes are available for configuration:\n\n+ `mib_template` (string - default: \"mibs/EXOMETER-METRICS-MIB.mib\")\u003cbr /\u003eSpecifies where to find the MIB template used for dynamically assembline an internal MIB. Take a look at the MIB template shipped with Exometer for reference in case you want to define your own template.\n\n+ `mib_dir` (string - default: \"tmp/exometer_report_snmp\")\u003cbr /\u003eSpecifies temporary direction which will be used by Exometer to store dymanically created MIB files.\n\n\n### \u003ca name=\"Creating_custom_exometer_entries\"\u003eCreating custom exometer entries\u003c/a\u003e ###\n\n\nPlease see @see exometer_entry documentation for details.\n\n\n### \u003ca name=\"Creating_custom_probes\"\u003eCreating custom probes\u003c/a\u003e ###\n\n\nPlease see @see exometer_probe documentation for details.\n\n\n### \u003ca name=\"Creating_custom_reporter_plugins\"\u003eCreating custom reporter plugins\u003c/a\u003e ###\n\n\nPlease see @see exometer_report documentation for details.\n\n\n### \u003ca name=\"Dependency_management\"\u003eDependency management\u003c/a\u003e ###\n\n\nExometer dependencies can be controlled using the `EXOMETER_PACKAGES`\nunix environment variable: a string listing packages or applications to\neither keep or remove, separated using space, tab or comma.\n\n\n#### \u003ca name=\"Syntax\"\u003eSyntax\u003c/a\u003e ####\n\n+ `(Package)` - use `Package` as a base. This will implicitly exclude all\n  applications not included in `Package`. See below for supported packages.\n\n+ `+(Package)` - add applications included in `Package`.\n\n+ `-(Package)` - remove applications in `Package` (except mandatory deps).\n\n+ `App` - keep application `App`.\n\n+ `+App` - keep application `App`.\n\n+ `-App` - exclude application `App`.\n\n\n#### \u003ca name=\"Supported_packages\"\u003eSupported packages\u003c/a\u003e ####\n\n+ `minimal` - only the mandatory deps: `lager`, `parse_trans`, `setup`.\n\n+ `basic` - (mandatory deps and) `folsom`.\n\n+ `amqp` - (mandatory deps and) `amqp_client`, `jiffy`.\n\n+ `full` - all of the above, plus `afunix` and `netlink`.\n\nExample - use only basic deps plus `afunix`\n\n```\n   EXOMETER_PACKAGES=\"(basic), +afunix\" make\n```\n\nExample - use all deps except the AMQP-related deps:\n\n```\n   export EXOMETER_PACKAGES=\"(full) -(amqp)\"\n```\n\n\n#### \u003ca name=\"Conditional_defines\"\u003eConditional defines\u003c/a\u003e ####\n\nFor each optional dependency that is included, a macro is defined,\nnamed `dep_App` - e.g. `dep_afunix`. Developers must not include\ncompile-time dependencies to optional applications, without checking\nthe corresponding macro and ensuring that the module compiles even\nwhen the dependent application is not included. See `exometer_report_amqp.erl`\nfor an example.\n\n\n#### \u003ca name=\"Customizing_rebar.config\"\u003eCustomizing rebar.config\u003c/a\u003e ####\n\nThe OS environment variables `EXOMETER_CONFIG_PREPROCESS` and\n`EXOMETER_CONFIG_POSTPROCESS` can be used to insert a script, similar to\n`rebar.config.script` in the processing flow of the exometer build.\n\nAs the names imply, the script given by `EXOMETER_CONFIG_PREPROCESS` (if any)\nwill be run before exometer does any processing of its own, and the\n`EXOMETER_CONFIG_POSTPROCESS` script (if any) will be run after all other\nprocessing is complete.\nThings that could be done in preprocessing: re-targeting a dependency,\nmodifying the list of predefined packages, etc.\n\n## Modules ##\n\n\n\u003ctable width=\"100%\" border=\"0\" summary=\"list of modules\"\u003e\n\u003ctr\u003e\u003ctd\u003e\u003ca href=\"https://github.com/Feuerlabs/exometer/blob/master/doc/exometer_netlink.md\" class=\"module\"\u003eexometer_netlink\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\u003ca href=\"https://github.com/Feuerlabs/exometer/blob/master/doc/exometer_report_amqp.md\" class=\"module\"\u003eexometer_report_amqp\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\u003ca href=\"https://github.com/Feuerlabs/exometer/blob/master/doc/exometer_report_graphite.md\" class=\"module\"\u003eexometer_report_graphite\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\u003ca href=\"https://github.com/Feuerlabs/exometer/blob/master/doc/exometer_report_opentsdb.md\" class=\"module\"\u003eexometer_report_opentsdb\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\u003ca href=\"https://github.com/Feuerlabs/exometer/blob/master/doc/exometer_report_snmp.md\" class=\"module\"\u003eexometer_report_snmp\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003ctr\u003e\u003ctd\u003e\u003ca href=\"https://github.com/Feuerlabs/exometer/blob/master/doc/exometer_report_statsd.md\" class=\"module\"\u003eexometer_report_statsd\u003c/a\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\n","funding_links":[],"categories":["Instrumenting / Monitoring","Monitoring","监控"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FFeuerlabs%2Fexometer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FFeuerlabs%2Fexometer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FFeuerlabs%2Fexometer/lists"}