{"id":21406669,"url":"https://github.com/ringcentral/metrics-facade","last_synced_at":"2025-09-15T14:05:17.928Z","repository":{"id":41202681,"uuid":"406056582","full_name":"ringcentral/metrics-facade","owner":"ringcentral","description":"RingCentral Metrics Facade is a Java library for working with metrics, allowing extremely flexible configuration of metrics and their export, designed to be generic and not tied to a specific implementation.","archived":false,"fork":false,"pushed_at":"2025-06-16T09:46:37.000Z","size":1194,"stargazers_count":23,"open_issues_count":27,"forks_count":4,"subscribers_count":9,"default_branch":"release_4-2","last_synced_at":"2025-07-11T23:03:06.247Z","etag":null,"topics":["hdrhistogram","histogram","java","jmx","metrics","monitring","open-source","prometheus","ringcentral","zabbix"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"devromik/metrics-facade","license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ringcentral.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-09-13T16:54:57.000Z","updated_at":"2025-05-07T14:17:26.000Z","dependencies_parsed_at":"2024-01-16T10:36:00.445Z","dependency_job_id":"d8043075-e9ed-43a8-897c-90efb411bb66","html_url":"https://github.com/ringcentral/metrics-facade","commit_stats":{"total_commits":164,"total_committers":6,"mean_commits":"27.333333333333332","dds":"0.20731707317073167","last_synced_commit":"1444de1cfb6b2ccc9aa7a363244abd22f390fcdd"},"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/ringcentral/metrics-facade","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ringcentral%2Fmetrics-facade","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ringcentral%2Fmetrics-facade/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ringcentral%2Fmetrics-facade/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ringcentral%2Fmetrics-facade/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ringcentral","download_url":"https://codeload.github.com/ringcentral/metrics-facade/tar.gz/refs/heads/release_4-2","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ringcentral%2Fmetrics-facade/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":275267381,"owners_count":25434616,"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","status":"online","status_checked_at":"2025-09-15T02:00:09.272Z","response_time":75,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["hdrhistogram","histogram","java","jmx","metrics","monitring","open-source","prometheus","ringcentral","zabbix"],"created_at":"2024-11-22T16:41:35.042Z","updated_at":"2025-09-15T14:05:17.907Z","avatar_url":"https://github.com/ringcentral.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# RingCentral Metrics Facade\n\n***RingCentral Metrics Facade*** *is a Java library for working with metrics,        \nallowing extremely flexible configuration of metrics and their export,         \ndesigned to be generic and not tied to a specific implementation.*      \n\nTable of Contents\n=================\n* [Main Features Overview](#main-features-overview)\n* [Getting Started](#getting-started)\n* [Features](#features)\n  * [Flexible Configuration](#flexible-configuration)\n  * [Labeled metrics](#labeled-metrics)\n  * [Prefix Label Values](#prefix-label-values)\n  * [Exclusions](#exclusions)\n  * [Slices and Levels](#slices-and-levels)\n* [Metrics](#metrics)\n  * [Counter](#counter)\n    * [Counter Config](#counter-config)\n  * [Rate](#rate)\n    * [Rate Config](#rate-config)\n  * [Histogram](#histogram)\n    * [Histogram Config](#histogram-config)\n  * [Timer](#timer)\n    * [Timer Config](#timer-config)\n  * [Var and CachingVar](#var-and-cachingvar)\n* [Metrics Reporters](#metrics-reporters)\n  * [PrometheusMetricsExporter](#prometheusmetricsexporter)\n  * [ZabbixMetricsJsonExporter and ZabbixLldMetricsReporter](#zabbixmetricsjsonexporter-and-zabbixlldmetricsreporter)\n  * [TelegrafMetricsJsonExporter](#telegrafmetricsjsonexporter)\n  * [JmxMetricsReporter](#jmxmetricsreporter)\n* [Metrics Producers](#metrics-producers)\n  * [SystemMetricsProducer](#systemmetricsproducer)\n  * [OperatingSystemMetricsProducer](#operatingsystemmetricsproducer)\n  * [GarbageCollectorsMetricsProducer](#garbagecollectorsmetricsproducer)\n  * [MemoryMetricsProducer](#memorymetricsproducer)\n  * [ThreadsMetricsProducer](#threadsmetricsproducer)\n  * [BufferPoolsMetricsProducer](#bufferpoolsmetricsproducer)\n* [Integration](#integration)\n  * [Dropwizard MetricRegistry](#dropwizard-MetricRegistry-integration)\n* [License](#license)  \n\n## Main Features Overview\n\n### Extremely flexible configuration\n\nYou can set up defaults and overrides for ***any*** subset of metrics  \n(by using a predicate) and ***almost any*** metric parameters.                  \nIn particular, you can specify a set of values to be ***calculated*** and ***exported***.            \nFor example, the implementation of a metric is not required to perform an expensive operation of        \ncalculating percentiles, if percentiles are not included in the set of values defined for this metric.           \nSee [Getting Started](#getting-started) for details and usage examples.        \n\n### Advanced support for labeled metrics\n\nIn particular, Metrics Facade supports eviction and expiration for labeled metrics,        \nthat is, for each labeled metric, it allows you to specify:        \n- the maximum number of combinations of label values:        \n  when this threshold is exceeded, the combination that has not been updated for the longest time,        \n  will be automatically removed (will not waste system resources)          \n- the expiration time for a combination of label values:  \n  if a combination has not been updated during this time, it will be automatically removed    \n\nSee [Getting Started](#getting-started) for details and usage examples.      \n\n## Getting Started\n\nLet us first introduce some important concepts that    \nwe will use in this section and throughout the document.    \n\n***Measurable value*** *is a typed value that can be measured.*  \n\nExamples: the number of requests processed, the number of requests    \nprocessed with errors, the average request processing time,    \nthe amount of free memory, the number of items in the queue.    \n\nEach measurable value has a type.      \nMeasurable value types are represented by subclasses of ```Measurable```.       \nExamples:         \n- ```Counter.COUNT``` (the number of requests processed)    \n- ```Histogram.MEAN``` (the average request processing time)  \n- ```Var.Value``` (the amount of free memory)  \n\n***Metric*** *is a typed named entity measuring a certain set of ```Measurable```s,    \nand providing the results of the measurements.*      \n\nEach metric has a type that supports a certain set of ```Measurable```s and  \na certain way of measuring them.\n\nMetric types are represented by subclasses of ```Metric```.     \nExamples:  \n- [Counter](#counter) is a ```java.lang.Long``` based counter,    \n  measuring exactly one value - the current value of the counter (```Counter.COUNT```).      \n  The measurement is performed by explicitly increasing or decreasing the counter:      \n  ```java \n  Counter requestErrorCounter = ... // COUNT = 0\n  requestErrorCounter.inc();        // COUNT = 1\n  requestErrorCounter.inc(2);       // COUNT = 3\n  requestErrorCounter.dec(2);       // COUNT = 1\n  ```\n\n- [Timer](#timer) measures the number of times something happens,      \n  the speed at which it happens (rate), and the statistical distribution of its duration:  \n    - ```Counter.COUNT``` (the number of times something happens)  \n    - ```Rate.MEAN_RATE``` (the mean rate)  \n    - ```Rate.ONE_MINUTE_RATE```\n    - ```Rate.FIVE_MINUTES_RATE```\n    - ```Rate.FIFTEEN_MINUTES_RATE```\n    - ```Rate.RATE_UNIT```\n    - ```Histogram.MIN``` (the min duration)  \n    - ```Histogram.MAX``` (the max duration)  \n    - ```Histogram.MEAN``` (the mean duration)  \n    - ```Histogram.STANDARD_DEVIATION```\n    - ```Histogram.Percentile``` (including the predefined ```PERCENTILE_5```, ```PERCENTILE_10```, ...)\n    - ```Timer.DURATION_UNIT```  \n\n  The measurement is performed by explicitly taking into account the durations:    \n  ```java \n  // Histogram.MAX = 0.0\n  // Histogram.MEAN = 0.0\n  Timer requestTimer = ...\n  \n  // Histogram.MAX = 10.0\n  // Histogram.MEAN = 10.0\n  requestTimer.update(10, NANOSECONDS);\n  \n  // Histogram.MAX = 20.0\n  // Histogram.MEAN = 15.0\n  requestTimer.update(20, NANOSECONDS); \n  \n  // Histogram.MAX = 30.0\n  // Histogram.MEAN = 20.0\n  requestTimer.update(30, NANOSECONDS); \n  ``` \n\nEach metric has a name represented by the ```MetricName``` class.  \n\n```Metric``` does not provide measurement results directly.    \nInstead, ```Metric``` provides the set of its instances (```MetricInstance```),    \nwhich, in turn, provide measurement results:    \n\n```java\ninterface Metric extends Iterable\u003cMetricInstance\u003e {\n    ...\n}\n\ninterface MetricInstance {\n    ...\n    Set\u003cMeasurable\u003e measurables();\n    \u003cV\u003e V valueOf(Measurable measurable) throws NotMeasuredException;\n}\n\n```\n\nThis design has been driven by the need to support labeled metrics.  \n\n***Labeled metric*** *is a metric with which a set of attributes (***labels***) is associated,      \nand which generates a separate \"child\" metric (represented by a ```MetricInstance```)    \nfor each involved (for which there was at least one update) combination of values of these attributes.*      \n\nLet us explain this definition with the following example 1,      \nthat we will use and develop throughout this section.  \n\nAssume you are developing an HTTP service that, in order to do its job, calls several other HTTP services.  \nEach of the external services is represented by several instances running on specific servers and ports.        \nThe service being developed can call any of these instances.      \n(for example, by using round-robin balancing).    \n\nLet us also assume that we would like to have a ***separate*** request execution [Timer](#timer)      \nfor each instance of an external service (that is, for each combination of service, server, and port         \n*for which at least one request has been made*).      \n\nIn other words, we would like to define a ***labeled [Timer](#timer)*** with the    \n***labels*** service, server, port (taking into account the order of the labels).  \n\nLet us now return to the concept of a metric instance (```MetricInstance```), and consider it in more detail.\n\nInstances are identified by a name (```MetricName```) which always starts with the metric's name (```MetricName```)          \n**and** a list of label values (```LabelValue```).          \nThere is also the set of ```Measurable```s associated with an instance.      \nThe instance allows you to get the value of any ```Measurable``` from this set (see ```instance.valueOf(m)``` below):  \n\n```java  \nCounter counter = registry.counter(withName(\"counter\"));\n\ncounter.inc();\ncounter.inc(2);\ncounter.dec();\n\ncounter.addListener(new MetricListener() {\n\n    @Override\n    public void metricInstanceAdded(MetricInstance instance) {\n        List\u003cString\u003e labelValuesString = instance.labelValues().stream()\n            .map(lv -\u003e lv.label().name() + \"=\" + lv.value())\n            .collect(toList());\n\n        String valuesString = \"{\" + instance.measurables().stream()\n            .map(m -\u003e m.getClass().getSimpleName() + \"=\" + instance.valueOf(m))\n            .collect(joining(\", \")) + \"}\";\n            \n        // You can also use the following \"snapshot-based\" approach for getting values:\n        // \n        // MeasurableValues values = instance.measurableValues();\n        // values.valueOf(m);    \n      \n        System.out.println(\n            \"Metric instance added:\\n\"\n            + \"  name = '\" + instance.name() + \"',\\n\"\n            + \"  label values = \" + instance.labelValues() + \",\\n\"\n            + \"  total instance = \" + instance.isTotalInstance() + \",\\n\"\n            + \"  labeled metric total instance = \" + instance.isLabeledMetricTotalInstance() + \",\\n\"\n            + \"  level instance = \" + instance.isLevelInstance() + \",\\n\"\n            + \"  measurable values = \" + valuesString);\n    }\n\n    @Override\n    public void metricInstanceRemoved(MetricInstance instance) {\n        System.out.println(\"Metric instance removed: name = '\" + instance.name() + \"'\");\n    }\n});\n``` \n\nOutput:\n```\nMetric instance added:\n  name = 'counter',\n  label values = [],\n  total instance = true,\n  labeled metric total instance = false,\n  level instance = false,\n  measurable values = {Count=2}\n```\n\nThe lifetime of some instances coincides with the lifetime of the metric,            \nwhile others can be added or removed when certain conditions are met.            \nBeing ```Iterable\u003cMetricInstance\u003e```, the metric provides the current set of instances (thread-safely).            \nThis feature is used by most exporters (see below).          \nIt's also possible to subscribe to the events ```metricInstanceAdded``` and ```metricInstanceRemoved```.        \nThis feature is used, for example, by ```JmxMetricsReporter```.  \n\nAn update of a metric is taken into account by the corresponding subset of instances.        \nBy default, only ***total instance*** is created along with the metric    \n(it can be disabled through metric configuration).        \nThe total instance takes all updates into account.        \nThe lifetime of the total instance is the same as the lifetime of the metric.    \nThis is the only instance created for non-labeled metrics.  \n\nIf the metric is labeled, an instance is created for each combination of ```LabelValue```s.        \nSuch an instance takes into account only those updates that are made for the corresponding combination:    \n\n```java  \nHistogram histogram = registry.histogram(\n    withName(\"histogram\"),\n    () -\u003e withHistogram()\n        .labels(SERVICE, SERVER, PORT)\n        .allSlice().noLevels());\n\n// updates the total instance and the instance service_1/server_1_1/111\nhistogram.update(10, forLabelValues(SERVICE.value(\"service_1\"), SERVER.value(\"server_1_1\"), PORT.value(\"111\"))); \n\n// updates the total instance and the instance service_1/server_1_12/121\nhistogram.update(20, forLabelValues(SERVICE.value(\"service_1\"), SERVER.value(\"server_1_2\"), PORT.value(\"121\")));\n\n// updates the total instance and the instance service_2/server_2_1/211\nhistogram.update(30, forLabelValues(SERVICE.value(\"service_2\"), SERVER.value(\"server_2_1\"), PORT.value(\"211\")));\n\n// updates the total instance and the instance service_2/server_2_1/212\nhistogram.update(40, forLabelValues(SERVICE.value(\"service_2\"), SERVER.value(\"server_2_1\"), PORT.value(\"212\")));\n\n// instances are added asynchronously\nThread.sleep(25);\n\nhistogram.forEach(instance -\u003e {\n    List\u003cString\u003e labelValuesString = instance.labelValues().stream()\n        .map(lv -\u003e lv.label().name() + \"=\" + lv.value())\n        .collect(toList());\n\n    // \"snapshot-based\" approach for getting values\n    MeasurableValues values = instance.measurableValues();\n\n    String valuesString = \"{\" + instance.measurables().stream()\n        // or instance.valueOf(m) but this approach is not \"snapshot-based\"\n        // and should not be used unnecessarily\n        .map(m -\u003e {\n            String name =\n                m instanceof Histogram.Percentile ?\n                \"Percentile_\" + ((Histogram.Percentile)m).quantileAsString() :\n                m.getClass().getSimpleName();\n\n            return name + \"=\" + values.valueOf(m);\n        })\n        .collect(joining(\", \")) + \"}\";\n\n    System.out.println(\n        \"Metric instance:\\n\"\n        + \"  name = '\" + instance.name() + \"',\\n\"\n        + \"  label values = \" + labelValuesString + \",\\n\"\n        + \"  total instance = \" + instance.isTotalInstance() + \",\\n\"\n        + \"  labeled metric total instance = \" + instance.isLabeledMetricTotalInstance() + \",\\n\"\n        + \"  level instance = \" + instance.isLevelInstance() + \",\\n\"\n        + \"  measurable values = \" + valuesString);\n});\n```\n\nOutput:\n```\nMetric instance:\n  name = 'histogram',\n  label values = [],\n  total instance = true,\n  labeled metric total instance = true,\n  level instance = false,\n  measurable values = {Count=4, Max=40, Percentile_0.9=40.0, Percentile_0.99=40.0, Percentile_0.5=30.0, Mean=25.0, Min=10}\n  \nMetric instance:\n  name = 'histogram',\n  label values = [service=service_1, server=server_1_1, port=111],\n  total instance = false,\n  labeled metric total instance = false,\n  level instance = false,\n  measurable values = {Count=1, Max=10, Percentile_0.9=10.0, Percentile_0.99=10.0, Percentile_0.5=10.0, Mean=10.0, Min=10}\n  \nMetric instance:\n  name = 'histogram',\n  label values = [service=service_1, server=server_1_2, port=121],\n  total instance = false,\n  labeled metric total instance = false,\n  level instance = false,\n  measurable values = {Count=1, Max=20, Percentile_0.9=20.0, Percentile_0.99=20.0, Percentile_0.5=20.0, Mean=20.0, Min=20}  \n  \nMetric instance:\n  name = 'histogram',\n  label values = [service=service_2, server=server_2_1, port=211],\n  total instance = false,\n  labeled metric total instance = false,\n  level instance = false,\n  measurable values = {Count=1, Max=30, Percentile_0.9=30.0, Percentile_0.99=30.0, Percentile_0.5=30.0, Mean=30.0, Min=30}  \n  \nMetric instance:\n  name = 'histogram',\n  label values = [service=service_2, server=server_2_1, port=212],\n  total instance = false,\n  labeled metric total instance = false,\n  level instance = false,\n  measurable values = {Count=1, Max=40, Percentile_0.9=40.0, Percentile_0.99=40.0, Percentile_0.5=40.0, Mean=40.0, Min=4}\n```\n\nThe life cycle of such an instance may end earlier the life cycle of the metric      \nin the case of an eviction or expiration (see [Labeled metrics](#labeled-metrics)),          \nas well as in the case of deregistering a list of label values for a variable (see [Var and Caching Var](#var-and-cachingvar)).    \n\nTo manage metrics, a special entity is used - metric registry.  \n \n***Metric registry*** *allows you to add and remove metrics, get the current set of metrics, and        \nsubscribe to an event of adding/removing a metric.*      \n\nA metric registry is represented by the ```MetricRegistry``` class.  \n\n```MetricRegistry``` implementations provide metric implementations.    \nCurrently, the following implementations are supported:\n- ```DefaultMetricRegistry```\n- ```DropwizardMetricRegistry``` based on https://metrics.dropwizard.io  \nIn the next versions, we plan to abandon this implementation in favor of ```DefaultMetricRegistry```\n\nLet us move on to practice and show how to implement the requirements from example 1      \nusing Metrics Facade. First, you need to add a number of dependencies:        \n\nBase (Core):\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.ringcentral.platform.metrics\u003c/groupId\u003e\n    \u003cartifactId\u003emetrics-facade-base\u003c/artifactId\u003e\n    \u003cversion\u003e4.2.0-RELEASE\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n```MetricRegistry``` implementation (for example, ```DefaultMetricRegistry```):\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.ringcentral.platform.metrics\u003c/groupId\u003e\n    \u003cartifactId\u003emetrics-facade-default-impl\u003c/artifactId\u003e\n    \u003cversion\u003e4.2.0-RELEASE\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nMetrics reporter(s) (for example, ```PrometheusMetricsExporter```):\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.ringcentral.platform.metrics\u003c/groupId\u003e\n    \u003cartifactId\u003emetrics-facade-prometheus\u003c/artifactId\u003e\n    \u003cversion\u003e4.2.0-RELEASE\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nLet's add metrics.    \nAt the moment, we have only one metric - a labeled [Timer](#timer) for requests to    \nexternal services with the labels service, server, and port.  \n\nA label is represented by the ```Label``` class.  \nLet's define the labels:    \n```java\nLabel SERVICE = new Label(\"service\");\nLabel SERVER = new Label(\"server\");\nLabel PORT = new Label(\"port\");\n```\n\nand add the metric using```MetricRegistry```:      \n\n```java\nMetricRegistry registry = new DefaultMetricRegistry();  \n...\n\nTimer httpClientRequestTimer = registry.timer(\n    withName(\"http\", \"client\", \"request\", \"duration\"),\n    () -\u003e withTimer().labels(SERVICE, SERVER, PORT));\n```\n\nThe next step is to update the metric.      \nTo do this, after executing a request to an external service,      \nit is necessary to record the time of its execution:     \n\n```java\n// in nanos\nlong requestDuration = ...\n\nhttpClientRequestTimer.update(\n    requestDuration, \n    forLabelValues(SERVICE.value(\"authorizationService\"), SERVER.value(\"127.0.0.1\"), PORT.value(\"7001\"))))\n```\n\nYou can also use the following recording scheme:    \n\n```java\n// start a stopwatch before executing the request    \nStopwatch stopwatch = fullConfigTimer.stopwatch(forLabelValues(\n    SERVICE.value(\"authorizationService\"), \n    SERVER.value(\"127.0.0.1\"), \n    PORT.value(\"7001\"))));\n...\n        \n// stop the stopwatch after executing the request    \nstopwatch.stop()\n```\n\nHere the question may arise, what is measured?  \nBy default, [Timer](#timer) measures the following values:  \n- ```Counter.COUNT```\n- ```Rate.MEAN_RATE```\n- ```Rate.ONE_MINUTE_RATE```\n- ```Rate.FIVE_MINUTES_RATE```\n- ```Rate.FIFTEEN_MINUTES_RATE```\n- ```Rate.RATE_UNIT```\n- ```Histogram.MIN```\n- ```Histogram.MAX```\n- ```Histogram.MEAN```\n- ```Histogram.PERCENTILE_50```\n- ```Histogram.PERCENTILE_90```\n- ```Histogram.PERCENTILE_99```\n- ```Timer.DURATION_UNIT```\n\nHowever, Metrics Facade allows for *extremely flexible configuration of metrics*.      \nIn particular, for each metric you can specify a set of values to be ***calculated*** and ***exported***.  \n\nSuppose, for example, that you have multiple timers in your project, and for most of them    \n(and the number of timers in an average project can reach several dozen)      \nyou want to measure ```Counter.COUNT```, ```Histogram.MAX```, ```Histogram.MEAN```, ```Histogram.PERCENTILE_90```,    \nbut for the timer for processing incoming HTTP requests you want to also measure    \n```Histogram.MIN```, ```Histogram.PERCENTILE_75```, ```Histogram.PERCENTILE_99```.    \n\nThis can be achieved as follows:    \n1) Set the required ***default*** values for timers:\n   ```java\n   registry.preConfigure(allMetrics(), modifying().timer(withTimer().measurables(\n       COUNT,\n       MAX, \n       MEAN, \n       PERCENTILE_90)));\n   ```\n\n2) Set the required set of values when defining the timer for processing    \n   incoming HTTP requests (the defaults will be overridden):  \n   ```java\n   Timer httpRequestTimer = registry.timer(\n      withName(\"http\", \"request\", \"duration\"),\n      () -\u003e withTimer().measurables(\n          COUNT,\n          MIN,\n          MAX,\n          MEAN,\n          PERCENTILE_75,\n          PERCENTILE_90,\n          PERCENTILE_99)\n   ```\n   ***or*** set the required ***default*** values for ```Timer``` with the appropriate name:  \n   ```java\n   registry.preConfigure(\n       // there may also be other predicates (for example, metricsMatchingNameMask (\"a.**.b\")),\n       // with which you can effectively configure any subset of metrics.\n       metricWithName(\"http\", \"request\", \"duration\"), \n       modifying().timer(withTimer().measurables(\n           COUNT,\n           MIN,\n           MAX,\n           MEAN,\n           PERCENTILE_75,\n           PERCENTILE_90,\n           PERCENTILE_99)));\n   ```\n\nThis configuration scheme allows:  \n\n- Set the configuration in one place without having to change the code of defining each metric involved.      \n- Optimize calculations and export.        \n  For example, the implementation of a metric is not required to perform an expensive operation of        \n  calculating percentiles, if percentiles are not included in the set of values defined for this metric.     \n  We plan to provide such implementations in one of the next major versions.        \n- Add (in future versions) support for new measurable values ***without breaking backward compatibility***.  \n  Unlike most other libraries for working with metrics, the Metrics Facade interfaces do not provide    \n  special methods for getting values of certain measured values (e.g. ```double Histogram.mean()```).      \n  Instead, methods are used that take ```Measurable``` as a parameter:        \n  ```MetricInstance.valueOf(Measurable)``` or        \n  ```MetricInstance.measurableValues().valueOf(Measurable)``` (a snapshot-based approach).    \n  This design allows the library to remain extremely flexible in terms of supporting new features.    \n  \nLet's add a counter of active client connections (sessions) to our project:    \n```java\nCounter activeClientConnectionCounter = registry.counter(withName(\"active\", \"client\", \"connections\"));\n```\n\nNow we have two metrics.       \nThese metrics live in memory, measuring certain values.      \nHowever, metrics are usually used to provide runtime information about an application instance.  \nIn order to do this, it is necessary not only to collect metrics but also to export them to  \nexternal monitoring systems that provide various means of visualizing and analyzing the collected metrics.  \nFor example, Prometheus (https://prometheus.io).   \n\nTo export metrics, metrics reporters are used ([Metrics Reporters](#metrics-reporters)).\n\n***Metrics reporter*** *allows you to present metrics in the format of a specific monitoring system;  \nsome reporters additionally send metrics to an external monitoring system in the appropriate format.*\n\nLet's add reporters for Prometheus and JMX:\n```java\nPrometheusMetricsExporter prometheusExporter = new PrometheusMetricsExporter(registry);\nnew PrometheusHttpServer(9095, prometheusExporter); // This server is for tests only\n\nregistry.addListener(new JmxMetricsReporter());\n```\n\nLet's assume that the following metric updates have been made:    \n```java\nhttpClientRequestTimer.update(\n    100L, MILLISECONDS,\n    forLabelValues(SERVICE.value(\"authorizationService\"), SERVER.value(\"127.0.0.1\"), PORT.value(\"7001\")));\n\nhttpClientRequestTimer.update(\n    200L, MILLISECONDS,\n    forLabelValues(SERVICE.value(\"authorizationService\"), SERVER.value(\"127.0.0.2\"), PORT.value(\"7002\")));\n\n// start a stopwatch before executing the request\nStopwatch stopwatch = httpClientRequestTimer.stopwatch(forLabelValues(\n    SERVICE.value(\"throttlingService\"),\n    SERVER.value(\"127.0.0.3\"),\n    PORT.value(\"7003\")));\n\nsleep(300L);\n\n// stop the stopwatch after executing the request\nstopwatch.stop();\n\nactiveClientConnectionCounter.inc();\nactiveClientConnectionCounter.inc();\nactiveClientConnectionCounter.inc();\nactiveClientConnectionCounter.dec();\n```\n\nLet's take a look at (slightly modified and formatted for better readability)    \nthe response of the test Prometheus server (http://localhost:9095/metrics):\n\n```java\n# TYPE http_client_request_duration summary\nhttp_client_request_duration_count{service=\"authorizationService\",server=\"127.0.0.1\",port=\"7001\",} 1.0\nhttp_client_request_duration{service=\"authorizationService\",server=\"127.0.0.1\",port=\"7001\",quantile=\"0.9\",} 100.0\nhttp_client_request_duration{service=\"authorizationService\",server=\"127.0.0.1\",port=\"7001\",quantile=\"0.99\",} 100.0\nhttp_client_request_duration{service=\"authorizationService\",server=\"127.0.0.1\",port=\"7001\",quantile=\"0.5\",} 100.0\n        \nhttp_client_request_duration_count{service=\"authorizationService\",server=\"127.0.0.2\",port=\"7002\",} 1.0\nhttp_client_request_duration{service=\"authorizationService\",server=\"127.0.0.2\",port=\"7002\",quantile=\"0.9\",} 200.0\nhttp_client_request_duration{service=\"authorizationService\",server=\"127.0.0.2\",port=\"7002\",quantile=\"0.99\",} 200.0\nhttp_client_request_duration{service=\"authorizationService\",server=\"127.0.0.2\",port=\"7002\",quantile=\"0.5\",} 200.0\n        \nhttp_client_request_duration_count{service=\"throttlingService\",server=\"127.0.0.3\",port=\"7003\",} 1.0\nhttp_client_request_duration{service=\"throttlingService\",server=\"127.0.0.3\",port=\"7003\",quantile=\"0.9\",} 300.692665\nhttp_client_request_duration{service=\"throttlingService\",server=\"127.0.0.3\",port=\"7003\",quantile=\"0.99\",} 300.692665\nhttp_client_request_duration{service=\"throttlingService\",server=\"127.0.0.3\",port=\"7003\",quantile=\"0.5\",} 300.692665\n        \n# TYPE http_client_request_duration_max gauge\nhttp_client_request_duration_max{service=\"authorizationService\",server=\"127.0.0.1\",port=\"7001\",} 100.0\nhttp_client_request_duration_max{service=\"authorizationService\",server=\"127.0.0.2\",port=\"7002\",} 200.0\nhttp_client_request_duration_max{service=\"throttlingService\",server=\"127.0.0.3\",port=\"7003\",} 300.692665        \n        \n# TYPE http_client_request_duration_mean gauge\nhttp_client_request_duration_mean{service=\"authorizationService\",server=\"127.0.0.1\",port=\"7001\",} 100.0\nhttp_client_request_duration_mean{service=\"authorizationService\",server=\"127.0.0.2\",port=\"7002\",} 200.0\nhttp_client_request_duration_mean{service=\"throttlingService\",server=\"127.0.0.3\",port=\"7003\",} 300.692665\n        \n# TYPE active_client_connections gauge\nactive_client_connections 2.0\n```\n\nNow let's assume that the servers and ports for external services are not statically configured,      \nand are periodically requested from a special external service named \"discoveryService\".      \nLet's also assume that we would not want the duration of requests to this \"auxiliary\" service      \nto affect the statistics for other services (\"business\" services).        \n\nThis can be achieved through exclusion of label values matching the corresponding predicate:        \n```java\nTimer httpClientRequestTimer = registry.timer(\n    withName(\"http\", \"client\", \"request\", \"duration\"),\n    () -\u003e withTimer()\n        .labels(SERVICE, SERVER, PORT)\n        .exclude(labelValuesMatchingAll(SERVICE.mask(\"discoveryService\"))));\n```\n\nThe following metric update will be ignored:    \n```java\nhttpClientRequestTimer.update(\n    100L, MILLISECONDS,\n    forLabelValues(SERVICE.value(\"discoveryService\"), SERVER.value(\"127.0.0.4\"), PORT.value(\"7004\")));\n```\n\nFurther, since services are discovered dynamically,          \nthe set of their server-port combinations can change over time.          \nThe set of ```MetricInstance```s of the timer will, accordingly, grow indefinitely.        \nSome of the ```MetricInstance```s will represent non-existent servers, and because    \nthey have already been exported to external monitoring systems, they are no longer needed,    \nbut at the same time they continue to consume resources (for example, memory).          \n\nTo solve this problem, Metrics Facade allows you to set for each metric:  \n- the maximum number of combinations of label values:          \n  when this threshold is exceeded, the combination that has not been updated for the longest time,          \n  will be automatically removed  \n- the expiration time for a combination of label values:    \n  if a combination has not been updated during this time, it will be automatically removed  \n  \nFor example:  \n\n```java\nTimer httpClientRequestTimer = registry.timer(\n    withName(\"http\", \"client\", \"request\", \"duration\"),\n    () -\u003e withTimer()\n        .labels(SERVICE, SERVER, PORT)\n        .exclude(labelValuesMatchingAll(SERVICE.mask(\"discoveryService\")))\n        .maxLabeledInstancesPerSlice(100) // eviction\n        .expireLabeledInstanceAfter(30, SECONDS)); // expiration\n```\n\nFurther, it would often be helpful to have:  \n1) a total ```MetricInstance``` for each service    \n   (taking all updates for this service into account)    \n2) a total ```MetricInstance``` for each service-server combination  \n3) a total ```MetricInstance``` for each server.    \n   Let's also assume that for such an instance, it is sufficient to measure only      \n   ```MAX```, ```MEAN```, and ```PERCENTILE_99```,        \n   and it is necessary to consider only updates for services whose name either starts with \"auth\" or        \n   contains the \"throttling\" substring, but at the same time exclude updates for port 7004      \n\nMetrics Facade offers the ability to ***automatically*** add this kind of        \n```MetricInstance```s through the functionality of slices and levels.         \n\n***Slice*** *is a child metric that takes into account only those updates of the parent metric     \nwhich satisfy the given ```LabelValuesPredicate```.      \nA slice can have its own configuration: name suffix, labels      \n(MUST be sublist if the parent metric's labels), measurable values, etc.*        \n\nBy default, a metric has only one slice - ```AllSlice``` taking all updates into account.    \n\n***Slice level*** *is a set of ```MetricInstance```s of the slice  \nfor the first ```k``` labels, ```k = 1..\u003clabel_count\u003e - 1```.*   \n\nFor example, if for a slice:    \n- three labels are defined: ```SERVICE```, ```SERVER```, ```PORT```  \n- levels are enabled  \n\nthen when updating this slice for the values             \n```SERVICE.value(\"service_1\")```, ```SERVER.value(\"server_1_1\")```, ```PORT.value(\"111\")```,      \nthe following ```MetricInstance```s will be created/updated:\n- ```SERVICE.value(\"service_1\")```, ```SERVER.value(\"server_1_1\")```, ```PORT.value(\"111\")```\n- ```SERVICE.value(\"service_1\")```, ```SERVER.value(\"server_1_1\")``` ***level instance***\n- ```SERVICE.value(\"service_1\")``` ***level instance***\n\nBy default, levels are enabled for ```AllSlice``` and disabled for other slices.  \nHere is how you can implement the above requirements using the functionality of slices and levels:  \n \n```java\nTimer httpClientRequestTimer = registry.timer(\n    withName(\"http\", \"client\", \"request\", \"duration\"),\n    () -\u003e withTimer()\n        .labels(SERVICE, SERVER, PORT)\n        ...\n        .allSlice()\n            .enableLevels() // enabled by default for AllSlice; implements 1) and 2)\n        .slice(\"by\", \"server\") // implements 3) \n            .predicate(labelValuesMatchingAll(\n                SERVICE.mask(\"auth*|*throttling*\"),\n                PORT.predicate(p -\u003e !p.equals(\"7004\"))))\n            .labels(SERVER)\n            .measurables(MAX, MEAN, PERCENTILE_99));\n```\n\nYou can find the complete sample ```GettingStartedSample.java``` in the following Maven module:    \n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.ringcentral.platform.metrics\u003c/groupId\u003e\n    \u003cartifactId\u003emetrics-facade-samples\u003c/artifactId\u003e\n    \u003cversion\u003e4.2.0-RELEASE\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n## Features\n\n### Flexible Configuration\n\nYou can set up defaults/overrides for ***any*** subset of metrics      \n(by using a predicate) and ***almost any*** metric parameters.                    \nIn particular, you can specify a set of values to be ***calculated*** and ***exported***.                \nFor example, the implementation of a metric is not required to perform an expensive operation of            \ncalculating percentiles, if percentiles are not included in the set of values defined for this metric.                \n\nExample of setting up defaults (```DefaultsSample.java```):  \n```java\nregistry.preConfigure(allMetrics(), modifying()\n    .metric(withMetric().prefix(labelValues(SAMPLE.value(\"defaults\"))))\n    .meter(withMeter()\n        .expireLabeledInstanceAfter(30, MINUTES)\n        .allSlice().noLevels())\n    .rate(withRate().measurables(COUNT, ONE_MINUTE_RATE))\n    .histogram(withHistogram().measurables(COUNT, MAX, MEAN, PERCENTILE_95))\n    .timer(withTimer().measurables(COUNT, ONE_MINUTE_RATE, MAX, MEAN, PERCENTILE_95)));\n```\n\nExample of setting up overrides (```OverridesSample.java```):  \n```java\nregistry.postConfigure(allMetrics(), modifying()\n    .metric(withMetric().prefix(labelValues(SAMPLE.value(\"overrides\"))))\n    .meter(withMeter()\n        .expireLabeledInstanceAfter(30, MINUTES)\n        .allSlice().noLevels())\n    .rate(withRate().measurables(COUNT, ONE_MINUTE_RATE))\n    .histogram(withHistogram().measurables(COUNT, MAX, MEAN, PERCENTILE_95))\n    .timer(withTimer().measurables(COUNT, ONE_MINUTE_RATE, MAX, MEAN, PERCENTILE_95)));\n```\n\n...for any subset of metrics and almost any parameters:    \n\n```java\nregistry.postConfigure(metricWithName(\"a.b.c\"), modifying().metric(withMetric().disable()));\nregistry.postConfigure(metricsWithNamePrefix(\"a.b\"), modifying().histogram(withHistogram().enable()));\nregistry.postConfigure(metricsMatchingNameMask(\"a.**.b\"), modifying().histogram(withHistogram().enable()));\n\nregistry.postConfigure(\n    metrics()\n        .including(metricsMatchingNameMask(\"a.b.**.d.**\")).excluding(metricWithName(\"a.b.c.d\"))\n        .including(metricsWithNamePrefix(\"d.e.f\")).excluding(metricsWithNamePrefix(\"d.e.f.g\")),\n    modifying().meter(withMeter().disable()));\n\nassert registry.timer(withName(\"a\", \"b\", \"c\", \"d\")).isEnabled();\nassert !registry.timer(withName(\"a\", \"b\", \"c\", \"d\", \"e\")).isEnabled(); // disabled\nassert !registry.timer(withName(\"a\", \"b\", \"x\", \"d\")).isEnabled(); // disabled\nassert !registry.timer(withName(\"d\", \"e\", \"f\")).isEnabled(); // disabled\nassert registry.timer(withName(\"d\", \"e\", \"f\", \"g\")).isEnabled();\nassert registry.timer(withName(\"d\", \"e\", \"f\", \"g\", \"h\")).isEnabled();\n```\n\nSee [Getting Started](#getting-started), ```DefaultsSample.java```,    \nand ```OverridesSample.java``` for more details and usage examples.    \n\n### Labeled metrics\n\nIn particular, Metrics Facade supports eviction and expiration for labeled metrics,        \nthat is, for each labeled metric, it allows you to specify:\n- the maximum number of combinations of label values:        \n  when this threshold is exceeded, the combination that has not been updated for the longest time,        \n  will be automatically removed (will not waste system resources)\n- the expiration time for a combination of label values:  \n  if a combination has not been updated during this time, it will be automatically removed\n  \n```LabeledMetricsEvictionAndExpirationSample.java```\n```java\nregistry.histogram(\n    withName(\"ActiveHealthChecker\", \"healthCheck\", \"attemptCount\", \"histogram\"),\n    () -\u003e withHistogram()\n        .labels(SERVICE, SERVER, PORT)\n        .maxLabeledInstancesPerSlice(5) // eviction\n        .expireLabeledInstanceAfter(1, MINUTES)); // expiration\n```\n\nSee [Getting Started](#getting-started) and ```LabeledMetricsEvictionAndExpirationSample.java```   \nfor more details and usage examples.    \n\n### Prefix Label Values\n\n```java\nregistry.postConfigure(\n    metricsMatchingNameMask(\"ActiveHealthChecker.**\"),\n    modifying().metric(withMetric().prefix(labelValues(SAMPLE.value(\"prefixLabelValues\")))));\n    \nregistry.histogram(\n    withName(\"ActiveHealthChecker\", \"healthCheck\", \"attemptCount\", \"histogram\"),\n    () -\u003e withHistogram().labels(SERVICE, SERVER, PORT));\n\nh.update(25, forLabelValues(\n    SERVICE.value(\"service_1\"), \n    SERVER.value(\"server_1_1\"), \n    PORT.value(\"7001\")));    \n```\n\nis the same as\n\n```java\nregistry.histogram(\n    withName(\"ActiveHealthChecker\", \"healthCheck\", \"attemptCount\", \"histogram\"),\n    () -\u003e withHistogram().labels(SAMPLE, SERVICE, SERVER, PORT));\n\nh.update(25, forLabelValues(\n    SAMPLE.value(\"prefixLabelValues\"),\n    SERVICE.value(\"service_1\"), \n    SERVER.value(\"server_1_1\"), \n    PORT.value(\"7001\")));    \n```\n\nSee ```PrefixLabelValuesSample.java``` for more details and usage examples.\n\n### Exclusions\n\nYou can drop the metric updates for label values matching a predicate:\n\n```ExclusionsSample.java```\n```java\nregistry.timer(\n    withName(\"ActiveHealthChecker\", \"healthCheck\"),\n    () -\u003e withTimer()\n        .labels(SERVICE, SERVER, PORT)\n        .exclude(labelValuesMatchingAny(\n            SERVER.mask(\"server_1_*|*2_1*\"),\n            PORT.predicate(p -\u003e p.equals(\"9001\")))));\n```\n\nSee [Getting Started](#getting-started) and ```ExclusionsSample.java``` for more details and usage examples.\n\n### Slices and Levels\n\n***Slice*** *is a child metric that takes into account only those updates of the parent metric       \nwhich satisfy the given ```LabelValuesPredicate```.      \nA slice can have its own configuration: name suffix, labels      \n(MUST be sublist if the parent metric's labels), measurable values, etc.*\n\nBy default, a metric has only one slice - ```AllSlice``` taking all updates into account.  \n\n***Slice level*** *is a set of ```MetricInstance```s of the slice    \nfor the first ```k``` labels, ```k = 1..\u003clabel_count\u003e - 1```.*  \n\nFor example, if for a slice:    \n- three labels are defined: ```SERVICE```, ```SERVER```, ```PORT```    \n- levels are enabled    \n\nthen when updating this slice for the values                 \n```SERVICE.value(\"service_1\")```, ```SERVER.value(\"server_1_1\")```, ```PORT.value(\"111\")```,        \nthe following ```MetricInstance```s will be created/updated:  \n- ```SERVICE.value(\"service_1\")```, ```SERVER.value(\"server_1_1\")```, ```PORT.value(\"111\")```  \n- ```SERVICE.value(\"service_1\")```, ```SERVER.value(\"server_1_1\")``` ***level instance***  \n- ```SERVICE.value(\"service_1\")``` ***level instance***  \n\nBy default, levels are enabled for ```AllSlice``` and disabled for other slices.    \nSee [Getting Started](#getting-started) and ```SlicesAndLevelsSample.java``` for more details and usage examples.    \n\n## Metrics\n\n### Counter\n\n```c.r.p.metrics.counter.Counter``` is a ```java.lang.Long``` based counter that can be increased or decreased:    \n\n```CounterSample.java```\n```java\n// Default config:\n//   no labels\n//   measurables: { COUNT }\nCounter defaultConfigCounter = registry.counter(withName(\"counter\", \"defaultConfig\"));\n\ndefaultConfigCounter.inc();\ndefaultConfigCounter.inc(2);\ndefaultConfigCounter.dec();\n```\n\nSupported measurables:  \n- ```Counter.COUNT```\n\n#### Counter Config\n\n```CounterSample.java```  \n```java\nCounter fullConfigCounter = registry.counter(\n    withName(\"counter\", \"fullConfig\"),\n    () -\u003e withCounter()\n        // options: disable(), enabled(boolean)\n        // default: enabled\n        .enable()\n\n        // default: no prefix label values\n        .prefix(labelValues(SAMPLE.value(\"counter\")))\n\n        // default: no labels\n        .labels(SERVICE, SERVER, PORT)\n\n        // options: noExclusions()\n        // default: no exclusions\n        .exclude(labelValuesMatchingAny(\n            SERVICE.mask(\"serv*2|serv*4*\"),\n            SERVER.mask(\"server_5\")))\n\n        // default: unlimited\n        .maxLabeledInstancesPerSlice(5)\n\n        // options: notExpireLabeledInstances()\n        // default: no expiration\n        .expireLabeledInstanceAfter(25, SECONDS)\n\n        // options: noMeasurables()\n        // default: { COUNT }\n        .measurables(COUNT)\n\n        // the properties specific to the metrics implementation\n        // default: no properties\n        .put(\"key_1\", \"value_1_1\")\n\n        .allSlice()\n            // options: disable(), enabled(boolean)\n            // default: enabled\n            .enable()\n\n            // default: the metric's labels [ SERVICE, SERVER, PORT ]\n            .labels(SERVICE, SERVER)\n\n            // options: noMaxLabeledInstances()\n            // default: the metric's maxLabeledInstancesPerSlice = 5\n            .maxLabeledInstances(10)\n\n            // options: notExpireLabeledInstances()\n            // default: the metric's expireLabeledInstanceAfter = 25 SECONDS\n            .expireLabeledInstanceAfter(42, SECONDS)\n\n            // options: noMeasurables() \n            // default: the metric's measurables { COUNT }\n            .measurables(COUNT)\n\n            // options: disableTotal(), noTotal(), totalEnabled(boolean)\n            // default: enabled\n            .enableTotal()\n\n            // options: disableLevels(), noLevels(), levelsEnabled(boolean)\n            // default: enabled\n            .enableLevels()\n\n            // the properties specific to the metrics implementation\n            // default: no properties (no overrides)\n            .put(\"key_1\", \"value_1_2\") // overrides \"key_1\" -\u003e \"value_1_1\"\n            .put(\"key_2\", \"value_2_1\")\n\n            .total(counterInstance()\n                // default: empty name suffix\n                .name(\"total\")\n\n                // options: noMeasurables()\n                // default: the slice's measurables { COUNT }\n                .measurables(COUNT)\n\n                // the properties specific to the metrics implementation\n                // default: no properties (no overrides)\n                .put(\"key_1\", \"value_1_2\") // overrides \"key_1\" -\u003e \"value_1_2\"\n                .put(\"key_2\", \"value_2_2\")) // overrides \"key_2\" -\u003e \"value_2_1\"\n        .slice(\"byService\")\n            // options: disable(), enabled(boolean)\n            // default: enabled\n            .enable()\n\n            // default: no predicate\n            .predicate(labelValuesMatchingAll(\n                SERVICE.mask(\"serv*_1*\"),\n                SERVER.predicate(s -\u003e s.equals(\"server_1_1\"))))\n\n            // default: no labels\n            .labels(SERVICE)\n\n            // options: noMaxLabeledInstances()\n            // default: the metric's maxLabeledInstancesPerSlice = 5\n            .maxLabeledInstances(2)\n\n            // options: notExpireLabeledInstances()\n            // default: the metric's expireLabeledInstanceAfter = 25 SECONDS\n            .expireLabeledInstanceAfter(42, SECONDS)\n\n            // options: noMeasurables()\n            // default: the metric's measurables { COUNT }\n            .measurables(COUNT)\n\n            // options: disableTotal(), noTotal(), totalEnabled(boolean)\n            // default: enabled\n            .enableTotal()\n\n            // options: disableLevels(), noLevels(), levelsEnabled(boolean)\n            // default: disabled\n            .enableLevels()\n\n            // the properties specific to the metrics implementation\n            // default: no properties (no overrides)\n            .put(\"key_1\", \"value_1_2\") // overrides \"key_1\" -\u003e \"value_1_1\"\n            .put(\"key_2\", \"value_2_1\")\n\n            .total(counterInstance()\n                // default: empty name suffix\n                .name(\"total\")\n\n                // options: noMeasurables()\n                // default: the slice's measurables { COUNT }\n                .measurables(COUNT)\n\n                // the properties specific to the metrics implementation\n                // default: no properties (no overrides)\n                .put(\"key_1\", \"value_1_2\") // overrides \"key_1\" -\u003e \"value_1_2\"\n                .put(\"key_2\", \"value_2_2\")) // overrides \"key_2\" -\u003e \"value_2_1\"\n);\n```\n\n### Rate\n\n```c.r.p.metrics.rate.Rate``` measures the number of times something happens (```Counter.COUNT```)  \nand the speed at which it happens\n(for example, the number of requests per ```Rate.RATE_UNIT```).\n\nSupported measurables:  \n- ```Counter.COUNT```\n- ```Rate.MEAN_RATE```\n- ```Rate.ONE_MINUTE_RATE```\n- ```Rate.FIVE_MINUTES_RATE```\n- ```Rate.FIFTEEN_MINUTES_RATE```\n- ```Rate.RATE_UNIT```\n\n```RateSample.java```\n```java\n// Default config:\n//   no labels\n//   measurables: {\n//     COUNT,\n//     MEAN_RATE,\n//     ONE_MINUTE_RATE,\n//     FIVE_MINUTES_RATE,\n//     FIFTEEN_MINUTES_RATE,\n//     RATE_UNIT\n//   }\nRate defaultConfigRate = registry.rate(withName(\"rate\", \"defaultConfig\"));\n\ndefaultConfigRate.mark();\ndefaultConfigRate.mark(2);\n```\n\n#### Rate Config\n\n```RateSample.java```\n```java\nRate fullConfigRate = registry.rate(\n    withName(\"rate\", \"fullConfig\"),\n    () -\u003e withRate()\n        // options: disable(), enabled(boolean)\n        // default: enabled\n        .enable()\n\n        // default: no prefix label values\n        .prefix(labelValues(SAMPLE.value(\"rate\")))\n\n        // default: no labels\n        .labels(SERVICE, SERVER, PORT)\n\n        // options: noExclusions()\n        // default: no exclusions\n        .exclude(labelValuesMatchingAny(\n            SERVICE.mask(\"serv*2|serv*4*\"),\n            SERVER.mask(\"server_5\")))\n\n        // default: unlimited\n        .maxLabeledInstancesPerSlice(5)\n\n        // options: notExpireLabeledInstances()\n        // default: no expiration\n        .expireLabeledInstanceAfter(25, SECONDS)\n\n        // options: noMeasurables()\n        // default: {\n        //   COUNT,\n        //   MEAN_RATE,\n        //   ONE_MINUTE_RATE,\n        //   FIVE_MINUTES_RATE,\n        //   FIFTEEN_MINUTES_RATE,\n        //   RATE_UNIT\n        // }\n        .measurables(COUNT)\n        \n        /**\n         * options:\n         *   - expMovingAverage() == {@link ExpMovingAverageRateImplConfigBuilder#expMovingAverage()},\n         *   - custom impl, e.g. countAndMean() == {@link CountScalingRateConfigBuilder#countScaling()}.\n         *     Custom impls must be registered: registry.extendWith(new CountScalingRateConfigBuilder()).\n         * default: expMovingAverage()\n         */\n        .impl(expMovingAverage())\n        // .impl(countScaling().factor(2)) // custom impl\n\n        // the properties specific to the metrics implementation\n        // default: no properties\n        .put(\"key_1\", \"value_1_1\")\n\n        .allSlice()\n            // options: disable(), enabled(boolean)\n            // default: enabled\n            .enable()\n\n            // default: the metric's labels [ SERVICE, SERVER, PORT ]\n            .labels(SERVICE, SERVER)\n\n            // options: noMaxLabeledInstances()\n            // default: the metric's maxLabeledInstancesPerSlice = 5\n            .maxLabeledInstances(10)\n\n            // options: notExpireLabeledInstances()\n            // default: the metric's expireLabeledInstanceAfter = 25 SECONDS\n            .expireLabeledInstanceAfter(42, SECONDS)\n\n            // options: noMeasurables()\n            // default: the metric's measurables { COUNT }\n            .measurables(COUNT, MEAN_RATE)\n\n            // options: disableTotal(), noTotal(), totalEnabled(boolean)\n            // default: enabled\n            .enableTotal()\n\n            // options: disableLevels(), noLevels(), levelsEnabled(boolean)\n            // default: enabled\n            .enableLevels()\n\n            // the properties specific to the metrics implementation\n            // default: no properties (no overrides)\n            .put(\"key_1\", \"value_1_2\") // overrides \"key_1\" -\u003e \"value_1_1\"\n            .put(\"key_2\", \"value_2_1\")\n\n            .total(rateInstance()\n                // default: empty name suffix\n                .name(\"total\")\n\n                // options: noMeasurables()\n                // default: the slice's measurables { COUNT, MEAN_RATE }\n                .measurables(\n                    COUNT,\n                    MEAN_RATE, ONE_MINUTE_RATE, FIVE_MINUTES_RATE,\n                    RATE_UNIT)\n\n                // the properties specific to the metrics implementation\n                // default: no properties (no overrides)\n                .put(\"key_1\", \"value_1_2\") // overrides \"key_1\" -\u003e \"value_1_2\"\n                .put(\"key_2\", \"value_2_2\")) // overrides \"key_2\" -\u003e \"value_2_1\"\n        .slice(\"byService\")\n            // options: disable(), enabled(boolean)\n            // default: enabled\n            .enable()\n\n            // default: no predicate\n            .predicate(labelValuesMatchingAll(\n                SERVICE.mask(\"serv*_1*\"),\n                SERVER.predicate(s -\u003e s.equals(\"server_1_1\"))))\n\n            // default: no labels\n            .labels(SERVICE)\n\n            // options: noMaxLabeledInstances()\n            // default: the metric's maxLabeledInstancesPerSlice = 5\n            .maxLabeledInstances(2)\n\n            // options: notExpireLabeledInstances()\n            // default: the metric's expireLabeledInstanceAfter = 25 SECONDS\n            .expireLabeledInstanceAfter(42, SECONDS)\n\n            // options: noMeasurables()\n            // default: the metric's measurables { COUNT }\n            .measurables(COUNT, ONE_MINUTE_RATE)\n\n            // options: disableTotal(), noTotal(), totalEnabled(boolean)\n            // default: enabled\n            .enableTotal()\n\n            // options: disableLevels(), noLevels(), levelsEnabled(boolean)\n            // default: disabled\n            .enableLevels()\n\n            // the properties specific to the metrics implementation\n            // default: no properties (no overrides)\n            .put(\"key_1\", \"value_1_2\") // overrides \"key_1\" -\u003e \"value_1_1\"\n            .put(\"key_2\", \"value_2_1\")\n\n            .total(rateInstance()\n                // default: empty name suffix\n                .name(\"total\")\n\n                // options: noMeasurables()\n                // default: the slice's measurables { COUNT, ONE_MINUTE_RATE }\n                .measurables(\n                    COUNT,\n                    MEAN_RATE, ONE_MINUTE_RATE, FIVE_MINUTES_RATE,\n                    RATE_UNIT)\n\n                // the properties specific to the metrics implementation\n                // default: no properties (no overrides)\n                .put(\"key_1\", \"value_1_2\") // overrides \"key_1\" -\u003e \"value_1_2\"\n                .put(\"key_2\", \"value_2_2\")) // overrides \"key_2\" -\u003e \"value_2_1\"\n);\n```\n\n### Histogram\n\n```c.r.p.metrics.histogram.Histogram``` measures the statistical distribution of ```java.lang.Long``` values.    \n\n```HistogramSample.java```\n```java\n// Default config:\n//   no labels\n//   measurables: {\n//     COUNT,\n//     MIN,\n//     MAX,\n//     MEAN,\n//     PERCENTILE_50,\n//     PERCENTILE_90,\n//     PERCENTILE_99\n//   }\nHistogram defaultConfigHistogram = registry.histogram(withName(\"histogram\", \"defaultConfig\"));\n\ndefaultConfigHistogram.update(1L);\ndefaultConfigHistogram.update(2L);\n```\n\nSupported measurables:  \n- ```Counter.COUNT```\n- ```Histogram.MIN```\n- ```Histogram.MAX```\n- ```Histogram.MEAN```\n- ```Histogram.STANDARD_DEVIATION```\n- ```Histogram.Percentile``` (including the predefined ```Histogram.PERCENTILE_5```, ```Histogram.PERCENTILE_10```, ...)\n- ```Histogram.Bucket``` (including the predefined ```Histogram.MS_10_BUCKET```, ```Histogram.SEC_1_BUCKET```, ...)  \n\n#### Histogram Config\n\n```HistogramSample.java```\n```java\nHistogram fullConfigHistogram = registry.histogram(\n    withName(\"histogram\", \"fullConfig\"),\n    () -\u003e withHistogram()\n        // options: disable(), enabled(boolean)\n        // default: enabled\n        .enable()\n\n        // default: no prefix label values\n        .prefix(labelValues(SAMPLE.value(\"histogram\")))\n\n        // default: no labels\n        .labels(SERVICE, SERVER, PORT)\n\n        // options: noExclusions()\n        // default: no exclusions\n        .exclude(labelValuesMatchingAny(\n            SERVICE.mask(\"serv*2|serv*4*\"),\n            SERVER.mask(\"server_5\")))\n\n        // default: unlimited\n        .maxLabeledInstancesPerSlice(5)\n\n        // options: notExpireLabeledInstances()\n        // default: no expiration\n        .expireLabeledInstanceAfter(25, SECONDS)\n\n        // options: noMeasurables()\n        // default: {\n        //   COUNT,\n        //   MIN,\n        //   MAX,\n        //   MEAN,\n        //   PERCENTILE_50,\n        //   PERCENTILE_90,\n        //   PERCENTILE_99\n        // }\n        .measurables(COUNT, MEAN)\n\n        // the properties specific to the metrics implementation\n        // default: no properties\n        .put(\"key_1\", \"value_1_1\")\n\n        /**\n         * options:\n         *   - hdr() == {@link HdrHistogramImplConfigBuilder#hdr()},\n         *   - scale() == {@link com.ringcentral.platform.metrics.defaultImpl.histogram.scale.configs.ScaleHistogramImplConfigBuilder#scale()},\n         *   - custom impl, e.g. countAndTotalSum() == {@link CountAndTotalSumScalingHistogramConfigBuilder#countAndTotalSumScaling()}.\n         *     Custom impls must be registered: registry.extendWith(new CountAndTotalSumScalingHistogramConfigBuilder()).\n         * default: hdr()\n         */\n        .impl(hdr()\n            .resetByChunks(6, Duration.ofMinutes(2))\n            .highestTrackableValue(1000, REDUCE_TO_HIGHEST_TRACKABLE)\n            .significantDigits(3)\n            .snapshotTtl(30, SECONDS))\n        // .impl(countAndTotalSumScaling().factor(2)) // custom impl\n\n        .allSlice()\n            // options: disable(), enabled(boolean)\n            // default: enabled\n            .enable()\n\n            // default: the metric's labels [ SERVICE, SERVER, PORT ]\n            .labels(SERVICE, SERVER)\n\n            // options: noMaxLabeledInstances()\n            // default: the metric's maxLabeledInstancesPerSlice = 5\n            .maxLabeledInstances(10)\n\n            // options: notExpireLabeledInstances()\n            // default: the metric's expireLabeledInstanceAfter = 25 SECONDS\n            .expireLabeledInstanceAfter(42, SECONDS)\n\n            // options: noMeasurables()\n            // default: the metric's measurables { COUNT, MEAN }\n            .measurables(COUNT, MEAN, MAX)\n\n            // options: disableTotal(), noTotal(), totalEnabled(boolean)\n            // default: enabled\n            .enableTotal()\n\n            // options: disableLevels(), noLevels(), levelsEnabled(boolean)\n            // default: enabled\n            .enableLevels()\n\n            // the properties specific to the metrics implementation\n            // default: no properties (no overrides)\n            .put(\"key_1\", \"value_1_2\") // overrides \"key_1\" -\u003e \"value_1_1\"\n            .put(\"key_2\", \"value_2_1\")\n\n            .total(histogramInstance()\n                // default: empty name suffix\n                .name(\"total\")\n\n                // options: noMeasurables()\n                // default: the slice's measurables { COUNT, MEAN, MAX }\n                .measurables(COUNT, MEAN, PERCENTILE_95, MAX, Bucket.of(1), Bucket.of(2))\n\n                // the properties specific to the metrics implementation\n                // default: no properties (no overrides)\n                .put(\"key_1\", \"value_1_2\") // overrides \"key_1\" -\u003e \"value_1_2\"\n                .put(\"key_2\", \"value_2_2\")) // overrides \"key_2\" -\u003e \"value_2_1\"\n        .slice(\"byService\")\n            // options: disable(), enabled(boolean)\n            // default: enabled\n            .enable()\n\n            // default: no predicate\n            .predicate(labelValuesMatchingAll(\n                SERVICE.mask(\"serv*_1*\"),\n                SERVER.predicate(s -\u003e s.equals(\"server_1_1\"))))\n\n            // default: no labels\n            .labels(SERVICE)\n\n            // options: noMaxLabeledInstances()\n            // default: the metric's maxLabeledInstancesPerSlice = 5\n            .maxLabeledInstances(2)\n\n            // options: notExpireLabeledInstances()\n            // default: the metric's expireLabeledInstanceAfter = 25 SECONDS\n            .expireLabeledInstanceAfter(42, SECONDS)\n\n            // options: noMeasurables()\n            // default: the metric's measurables { COUNT, MEAN }\n            .measurables(\n                COUNT,\n                TOTAL_SUM,\n                MEAN,\n                PERCENTILE_50,\n                PERCENTILE_95,\n                MAX,\n                Buckets.of(points(0, 1, 24, 25, 30, 49, 50, 55)))\n\n            // options: disableTotal(), noTotal(), totalEnabled(boolean)\n            // default: enabled\n            .enableTotal()\n\n            // options: disableLevels(), noLevels(), levelsEnabled(boolean)\n            // default: disabled\n            .enableLevels()\n\n            // the properties specific to the metrics implementation\n            // default: no properties (no overrides)\n            .put(\"key_1\", \"value_1_2\") // overrides \"key_1\" -\u003e \"value_1_1\"\n            .put(\"key_2\", \"value_2_1\")\n\n            .total(histogramInstance()\n                // default: empty name suffix\n                .name(\"total\")\n\n                // options: noMeasurables()\n                // default: the slice's measurables { COUNT, MEAN, PERCENTILE_50, PERCENTILE_95, MAX }\n                .measurables(COUNT, MIN, MEAN, MAX)\n\n                // the properties specific to the metrics implementation\n                // default: no properties (no overrides)\n                .put(\"key_1\", \"value_1_2\") // overrides \"key_1\" -\u003e \"value_1_2\"\n                .put(\"key_2\", \"value_2_2\")) // overrides \"key_2\" -\u003e \"value_2_1\"\n);\n```\n\n### Timer\n\n```c.r.p.metrics.timer.Timer``` measures the number of times something happens,      \nthe speed at which it happens (rate), and the statistical distribution of its duration.     \nIn fact, it combines ```Rate``` and ```Histogram```.         \n\nSupported measurables:  \n- ```Counter.COUNT```\n- ```Rate.MEAN_RATE```\n- ```Rate.ONE_MINUTE_RATE```\n- ```Rate.FIVE_MINUTES_RATE```\n- ```Rate.FIFTEEN_MINUTES_RATE```\n- ```Rate.RATE_UNIT```\n- ```Histogram.MIN```\n- ```Histogram.MAX```\n- ```Histogram.MEAN```\n- ```Histogram.STANDARD_DEVIATION```\n- ```Histogram.Percentile``` (including the predefined ```Histogram.PERCENTILE_5```, ```Histogram.PERCENTILE_10```, ...)\n- ```Histogram.Bucket``` (including the predefined ```Histogram.MS_10_BUCKET```, ```Histogram.SEC_1_BUCKET```, ...)\n- ```Timer.DURATION_UNIT```\n\n#### Timer Config\n\n```TimerSample.java```\n```java\nTimer fullConfigTimer = registry.timer(\n    withName(\"timer\", \"fullConfig\"),\n    () -\u003e withTimer()\n        // options: disable(), enabled(boolean)\n        // default: enabled\n        .enable()\n\n        // default: no prefix label values\n        .prefix(labelValues(SAMPLE.value(\"timer\")))\n    \n        // default: no labels\n        .labels(SERVICE, SERVER, PORT)\n    \n        // options: noExclusions()\n        // default: no exclusions\n        .exclude(labelValuesMatchingAny(\n            SERVICE.mask(\"serv*2|serv*4*\"),\n            SERVER.mask(\"server_5\")))\n    \n        // default: unlimited\n        .maxLabeledInstancesPerSlice(5)\n    \n        // options: notExpireLabeledInstances()\n        // default: no expiration\n        .expireLabeledInstanceAfter(25, SECONDS)\n    \n        // options: noMeasurables()\n        // default: {\n        //   Counter.COUNT,\n        //\n        //   Rate.MEAN_RATE,\n        //   Rate.ONE_MINUTE_RATE,\n        //   Rate.FIVE_MINUTES_RATE,\n        //   Rate.FIFTEEN_MINUTES_RATE,\n        //   Rate.RATE_UNIT,\n        //\n        //   Histogram.MIN,\n        //   Histogram.MAX,\n        //   Histogram.MEAN,\n        //   Histogram.PERCENTILE_50,\n        //   Histogram.PERCENTILE_90,\n        //   Histogram.PERCENTILE_99,\n        //\n        //   Timer.DURATION_UNIT\n        // }\n        .measurables(COUNT, MEAN_RATE, MAX, MEAN)\n    \n        // the properties specific to the metrics implementation\n        // default: no properties\n        .put(\"key_1\", \"value_1_1\")\n\n        /**\n         * options:\n         *   - expMovingAverage() == {@link ExpMovingAverageRateImplConfigBuilder#expMovingAverage()},\n         *   - custom impl, e.g. countAndMean() == {@link CountScalingRateConfigBuilder#countScaling()}.\n         *     Custom impls must be registered: registry.extendWith(new CountScalingRateConfigBuilder()).\n         * default: expMovingAverage()\n         */\n        .impl(expMovingAverage())\n        // .impl(countScaling().factor(2)) // custom impl\n\n        /**\n         * options:\n         *   - hdr() == {@link HdrHistogramImplConfigBuilder#hdr()},\n         *   - scale() == {@link com.ringcentral.platform.metrics.defaultImpl.histogram.scale.configs.ScaleHistogramImplConfigBuilder#scale()},\n         *   - custom impl, e.g. countAndTotalSum() == {@link CountAndTotalSumScalingHistogramConfigBuilder#countAndTotalSumScaling()}.\n         *     Custom impls must be registered: registry.extendWith(new CountAndTotalSumScalingHistogramConfigBuilder()).\n         * default: hdr()\n         */\n        .impl(hdr()\n            .resetByChunks(6, Duration.ofMinutes(2))\n            .lowestDiscernibleValue(MILLISECONDS.toNanos(1))\n            .highestTrackableValue(DAYS.toNanos(7), REDUCE_TO_HIGHEST_TRACKABLE)\n            .significantDigits(2)\n            .snapshotTtl(30, SECONDS))\n        // .impl(countAndTotalSumScaling().factor(2)) // custom impl\n\n        .allSlice()\n            // options: disable(), enabled(boolean)\n            // default: enabled\n            .enable()\n    \n            // default: the metric's labels [ SERVICE, SERVER, PORT ]\n            .labels(SERVICE, SERVER)\n    \n            // options: noMaxLabeledInstances()\n            // default: the metric's maxLabeledInstancesPerSlice = 5\n            .maxLabeledInstances(10)\n    \n            // options: notExpireLabeledInstances()\n            // default: the metric's expireLabeledInstanceAfter = 25 SECONDS\n            .expireLabeledInstanceAfter(42, SECONDS)\n    \n            // options: noMeasurables()\n            // default: the metric's measurables { COUNT, MEAN_RATE, MAX, MEAN }\n            .measurables(COUNT, MEAN_RATE, MAX, MEAN, PERCENTILE_50)\n    \n            // options: disableTotal(), noTotal(), totalEnabled(boolean)\n            // default: enabled\n            .enableTotal()\n    \n            // options: disableLevels(), noLevels(), levelsEnabled(boolean)\n            // default: enabled\n            .enableLevels()\n    \n            // the properties specific to the metrics implementation\n            // default: no properties (no overrides)\n            .put(\"key_1\", \"value_1_2\") // overrides \"key_1\" -\u003e \"value_1_1\"\n            .put(\"key_2\", \"value_2_1\")\n    \n            .total(timerInstance()\n                // default: empty name suffix\n                .name(\"total\")\n    \n                // options: noMeasurables()\n                // default: the slice's measurables { COUNT, MEAN_RATE, MAX, MEAN, PERCENTILE_50 }\n                .measurables(COUNT, MEAN_RATE, MAX, MEAN, PERCENTILE_50, PERCENTILE_90)\n    \n                // the properties specific to the metrics implementation\n                // default: no properties (no overrides)\n                .put(\"key_1\", \"value_1_2\") // overrides \"key_1\" -\u003e \"value_1_2\"\n                .put(\"key_2\", \"value_2_2\")) // overrides \"key_2\" -\u003e \"value_2_1\"\n        .slice(\"byService\")\n            // options: disable(), enabled(boolean)\n            // default: enabled\n            .enable()\n    \n            // default: no predicate\n            .predicate(labelValuesMatchingAll(\n                SERVICE.mask(\"serv*_1*\"),\n                SERVER.predicate(s -\u003e s.equals(\"server_1_1\"))))\n    \n            // default: no labels\n            .labels(SERVICE)\n    \n            // options: noMaxLabeledInstances()\n            // default: the metric's maxLabeledInstancesPerSlice = 5\n            .maxLabeledInstances(2)\n    \n            // options: notExpireLabeledInstances()\n            // default: the metric's expireLabeledInstanceAfter = 25 SECONDS\n            .expireLabeledInstanceAfter(42, SECONDS)\n    \n            // options: noMeasurables()\n            // default: the metric's measurables { COUNT, MEAN_RATE, MAX, MEAN }\n            .measurables(\n                COUNT,\n                MEAN_RATE,\n                MAX,\n                MEAN,\n                PERCENTILE_75,\n                MS_10_BUCKET,\n                MS_30_BUCKET,\n                MS_50_BUCKET,\n                MS_75_BUCKET,\n                MS_100_BUCKET,\n                MS_250_BUCKET)\n\n            // options: disableTotal(), noTotal(), totalEnabled(boolean)\n            // default: enabled\n            .enableTotal()\n    \n            // options: disableLevels(), noLevels(), levelsEnabled(boolean)\n            // default: disabled\n            .enableLevels()\n    \n            // the properties specific to the metrics implementation\n            // default: no properties (no overrides)\n            .put(\"key_1\", \"value_1_2\") // overrides \"key_1\" -\u003e \"value_1_1\"\n            .put(\"key_2\", \"value_2_1\")\n    \n            .total(timerInstance()\n                // default: empty name suffix\n                .name(\"total\")\n    \n                // options: noMeasurables()\n                // default: the slice's measurables { COUNT, MEAN_RATE, MAX, MEAN, PERCENTILE_75 }\n                .measurables(COUNT, MEAN_RATE, MIN, MAX, MEAN, PERCENTILE_75, PERCENTILE_90)\n    \n                // the properties specific to the metrics implementation\n                // default: no properties (no overrides)\n                .put(\"key_1\", \"value_1_2\") // overrides \"key_1\" -\u003e \"value_1_2\"\n                .put(\"key_2\", \"value_2_2\")) // overrides \"key_2\" -\u003e \"value_2_1\"\n);\n```\n\n### Var and CachingVar\n\n```c.r.p.metrics.var.Var``` is an arbitrary (possibly cached) value of a specific type       \n(```[Caching]ObjectVar```, ```[Caching]LongVar```, ```[Caching]DoubleVar```, ```[Caching]StringVar``` are supported)       \nthat can change over time.    \n\n```VarSample.java```\n```java\nAtomicLong valueSupplier_1 = new AtomicLong();\n\n// Supported var types: ObjectVar, LongVar, DoubleVar, StringVar\nLongVar defaultConfigVar = registry.longVar(\n    withName(\"var\", \"defaultConfig\"),\n    () -\u003e valueSupplier_1.incrementAndGet());\n\nAtomicLong valueSupplier_2 = new AtomicLong();\n\nLongVar fullConfigVar = registry.longVar(\n    withName(\"var\", \"fullConfig\"),\n\n    // options: Var.noTotal()\n    () -\u003e valueSupplier_2.incrementAndGet(),\n\n    () -\u003e withLongVar()\n        // options: disable(), enabled(boolean)\n        // default: enabled\n        .enable()\n\n        // default: no prefix label values\n        .prefix(labelValues(SAMPLE.value(\"var\")))\n\n        .labels(SERVICE, SERVER, PORT)\n\n        // the properties specific to the metrics implementation\n        // default: no properties\n        .put(\"key\", \"value\"));\n\nAtomicLong valueSupplier_3 = new AtomicLong();\n\nfullConfigVar.register(\n    () -\u003e valueSupplier_3.incrementAndGet(),\n    forLabelValues(SERVICE.value(\"service_1\"), SERVER.value(\"server_1_1\"), PORT.value(\"111\")));\n\nAtomicLong valueSupplier_4 = new AtomicLong();\n\nfullConfigVar.register(\n    () -\u003e valueSupplier_4.incrementAndGet(),\n    forLabelValues(SERVICE.value(\"service_2\"), SERVER.value(\"server_2_1\"), PORT.value(\"211\")));\n\nfullConfigVar.deregister(labelValues(\n    SERVICE.value(\"service_1\"),\n    SERVER.value(\"server_1_1\"),\n    PORT.value(\"111\")));\n\nAtomicLong valueSupplier_5 = new AtomicLong();\n\n// Supported caching var types:\n//   CachingObjectVar,\n//   CachingLongVar,\n//   CachingDoubleVar,\n//   CachingStringVar\nCachingDoubleVar defaultConfigCachingVar = registry.cachingDoubleVar(\n    withName(\"cachingVar\", \"defaultConfig\"),\n    () -\u003e valueSupplier_5.incrementAndGet() + 0.5);\n\nAtomicLong valueSupplier_6 = new AtomicLong();\n\nCachingDoubleVar fullConfigCachingVar = registry.cachingDoubleVar(\n    withName(\"cachingVar\", \"fullConfig\"),\n\n    // options: Var.noTotal()\n    () -\u003e valueSupplier_6.incrementAndGet() + 0.5,\n\n    () -\u003e withCachingDoubleVar()\n        // options: disable(), enabled(boolean)\n        // default: enabled\n        .enable()\n\n        // default: no prefix label values\n        .prefix(labelValues(SAMPLE.value(\"var\")))\n\n        .labels(SERVICE, SERVER, PORT)\n\n        // default: 30 SECONDS\n        .ttl(10, SECONDS)\n\n        // the properties specific to the metrics implementation\n        // default: no properties\n        .put(\"key\", \"value\"));\n```\n\n## Metrics Reporters\n\nTypically, metrics are used to provide runtime information about an application instance.  \nIn order to do this, it is necessary not only to collect metrics but also to export them to    \nexternal monitoring systems that provide various means of visualizing and analyzing the collected metrics.    \nFor example, Prometheus (https://prometheus.io).  \n\n***Metrics reporter*** *allows you to present metrics in the format of a specific monitoring system;  \nsome reporters additionally send metrics to an external monitoring system in the appropriate format.*\n\nThe following describes the reporters provided by the library out of the box.\n\n### PrometheusMetricsExporter\n\n```PrometheusMetricsExporter``` exports metrics in the Prometheus format (https://prometheus.io).\n\nDependencies:\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.ringcentral.platform.metrics\u003c/groupId\u003e\n    \u003cartifactId\u003emetrics-facade-prometheus\u003c/artifactId\u003e\n    \u003cversion\u003e4.2.0-RELEASE\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nNote that ```metrics-facade-prometheus``` uses\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eio.prometheus\u003c/groupId\u003e\n    \u003cartifactId\u003esimpleclient_common\u003c/artifactId\u003e\n    \u003cversion\u003e...\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nIn case of conflict between the ```simpleclient_common``` version used in ```Metrics Facade``` and the one used in your project, you can resolve it with ```dependency.exclusions``` or any other available means. For example, see ```metrics-facade-samples/pom.xml```:\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.ringcentral.platform.metrics\u003c/groupId\u003e\n    \u003cartifactId\u003emetrics-facade-prometheus\u003c/artifactId\u003e\n    \u003cversion\u003e${project.version}\u003c/version\u003e\n\n    \u003cexclusions\u003e\n        \u003cexclusion\u003e\n            \u003cgroupId\u003eio.prometheus\u003c/groupId\u003e\n            \u003cartifactId\u003esimpleclient_common\u003c/artifactId\u003e\n        \u003c/exclusion\u003e\n    \u003c/exclusions\u003e\n\u003c/dependency\u003e\n```\n\nExample:\n```java\nMetricRegistry registry = new DefaultMetricRegistry();\nPrometheusMetricsExporter exporter = new PrometheusMetricsExporter(registry);\n\nHistogram h = registry.histogram(\n    withName(\"histogram\"),\n    () -\u003e withHistogram()\n        .labels(SERVICE, SERVER, PORT)\n        .measurables(MAX, MEAN));\n\nh.update(1, forLabelValues(SERVICE.value(\"service_1\"), SERVER.value(\"server_1_1\"), PORT.value(\"111\")));\nh.update(2, forLabelValues(SERVICE.value(\"service_1\"), SERVER.value(\"server_1_2\"), PORT.value(\"121\")));\nh.update(3, forLabelValues(SERVICE.value(\"service_2\"), SERVER.value(\"server_2_1\"), PORT.value(\"211\")));\n\n// Metric instances are added asynchronously\nsleep(25); \n\nSystem.out.println(exporter.exportMetrics());\n```\n\nOutput (simplified):\n```bash\n# TYPE histogram_max gauge\nhistogram_max{service=\"service_1\",server=\"server_1_1\",port=\"111\",} 1.0\nhistogram_max{service=\"service_1\",server=\"server_1_2\",port=\"121\",} 2.0\nhistogram_max{service=\"service_2\",server=\"server_2_1\",port=\"211\",} 3.0\n\n# TYPE histogram_mean gauge\nhistogram_mean{service=\"service_1\",server=\"server_1_1\",port=\"111\",} 1.0\nhistogram_mean{service=\"service_1\",server=\"server_1_2\",port=\"121\",} 2.0\nhistogram_mean{service=\"service_2\",server=\"server_2_1\",port=\"211\",} 3.0\n```\n\nIf you want to modify the export (change the names, disable some metrics or measured values, etc.),    \nyou need to configure the ```PrometheusMetricsExporter``` accordingly:  \n\n```PrometheusMetricsExporterSample.java```\n```java\nMetricRegistry registry = new DefaultMetricRegistry();\n\n// Default config\n// PrometheusMetricsExporter prometheusMetricsExporter = new PrometheusMetricsExporter(registry);\n\nPrometheusInstanceSampleSpecProvider miSampleSpecProvider = new PrometheusInstanceSampleSpecProvider(\n    true, // exportTotalInstances. defaults to true\n    false, // exportLabeledTotalInstances. defaults to false\n    false); // exportLevelInstances. defaults to true\n\nPrometheusInstanceSampleSpecModsProvider miSampleSpecModsProvider = new PrometheusInstanceSampleSpecModsProvider();\n\nmiSampleSpecModsProvider.addMod(\n    forMetricInstancesMatching(\n        nameMask(\"Histogram.**\"),\n        instance -\u003e \"service_2\".equals(instance.valueOf(SERVICE))),\n    (metric, instance, currSpec) -\u003e instanceSampleSpec().disable());\n\nmiSampleSpecModsProvider.addMod(\n    forMetricWithName(\"Histogram\"),\n    (metric, instance, currSpec) -\u003e instanceSampleSpec()\n        .name(instance.name().withNewPart(instance.valueOf(SERVICE)))\n        .labelValues(currSpec.labelValuesWithout(SERVICE)));\n\nmiSampleSpecModsProvider.addMod(\n    forMetricsWithNamePrefix(\"Histogram\"),\n    (metric, instance, currSpec) -\u003e\n        instanceSampleSpec().name(currSpec.name().replaceLast(currSpec.name().lastPart() + \"_svc\")));\n\nPrometheusInstanceSamplesProducer miSamplesProducer = new PrometheusInstanceSamplesProducer(\n    null, // totalInstanceNameSuffix. defaults to null that means no suffix\n    \"all\"); // labeledMetricTotalInstanceNameSuffix. defaults to \"all\"\n\nPrometheusSampleSpecProvider sampleSpecProvider = new PrometheusSampleSpecProvider();\nPrometheusSampleSpecModsProvider sampleSpecModsProvider = new PrometheusSampleSpecModsProvider();\n\nsampleSpecModsProvider.addMod(\n    forMetricInstancesMatching(\n        nameMask(\"Histogram.**\"),\n        instance -\u003e instance instanceof HistogramInstance),\n    (instanceSampleSpec, instance, measurableValues, measurable, currSpec) -\u003e\n        measurable instanceof Max ? sampleSpec().disable() : sampleSpec());\n\nPrometheusSamplesProducer samplesProducer = new PrometheusSamplesProducer();\n\nPrometheusInstanceSamplesProvider miSamplesProvider = new PrometheusInstanceSamplesProvider(\n    miSampleSpecProvider,\n    miSampleSpecModsProvider,\n    miSamplesProducer,\n    sampleSpecProvider,\n    sampleSpecModsProvider,\n    samplesProducer,\n    registry);\n\nPrometheusMetricsExporter exporter = new PrometheusMetricsExporter(\n    true,\n    Locale.ENGLISH,\n    miSamplesProvider);\n\nHistogram h = registry.histogram(\n    withName(\"Histogram\"),\n    () -\u003e withHistogram()\n        .description(\"Histogram for \" + PrometheusMetricsExporterSample.class.getSimpleName())\n        .labels(SERVICE, SERVER, PORT)\n        .measurables(MIN, MAX, MEAN));\n\nh.update(1, forLabelValues(SERVICE.value(\"service_1\"), SERVER.value(\"server_1_1\"), PORT.value(\"111\")));\nh.update(2, forLabelValues(SERVICE.value(\"service_1\"), SERVER.value(\"server_1_1\"), PORT.value(\"111\")));\nh.update(3, forLabelValues(SERVICE.value(\"service_1\"), SERVER.value(\"server_1_2\"), PORT.value(\"121\")));\nh.update(4, forLabelValues(SERVICE.value(\"service_2\"), SERVER.value(\"server_2_1\"), PORT.value(\"211\")));\n\nTimer t = registry.timer(\n    withName(\"Timer\"),\n    () -\u003e withTimer()\n        .description(\"Timer for \" + PrometheusMetricsExporterSample.class.getSimpleName())\n        .labels(SERVICE, SERVER, PORT)\n        .measurables(MIN, MAX, MEAN));\n\nt.update(SECONDS.toNanos(1), forLabelValues(SERVICE.value(\"service_1\"), SERVER.value(\"server_1_1\"), PORT.value(\"111\")));\nt.update(SECONDS.toNanos(2), forLabelValues(SERVICE.value(\"service_1\"), SERVER.value(\"server_1_2\"), PORT.value(\"121\")));\nt.update(SECONDS.toNanos(3), forLabelValues(SERVICE.value(\"service_2\"), SERVER.value(\"server_2_1\"), PORT.value(\"211\")));\n```\n\nOutput:  \n```bash\n# HELP histogram_service_1_svc_mean Histogram for PrometheusMetricsExporterSample\n# TYPE histogram_service_1_svc_mean gauge\nhistogram_service_1_svc_mean{server=\"server_1_1\",port=\"111\",} 1.5\nhistogram_service_1_svc_mean{server=\"server_1_2\",port=\"121\",} 3.0\n# HELP histogram_service_1_svc_min Histogram for PrometheusMetricsExporterSample\n# TYPE histogram_service_1_svc_min gauge\nhistogram_service_1_svc_min{server=\"server_1_1\",port=\"111\",} 1.0\nhistogram_service_1_svc_min{server=\"server_1_2\",port=\"121\",} 3.0\n# HELP timer_max Timer for PrometheusMetricsExporterSample\n# TYPE timer_max gauge\ntimer_max{service=\"service_1\",server=\"server_1_1\",port=\"111\",} 1.002438655\ntimer_max{service=\"service_1\",server=\"server_1_2\",port=\"121\",} 2.004877311\ntimer_max{service=\"service_2\",server=\"server_2_1\",port=\"211\",} 3.003121663\n# HELP timer_mean Timer for PrometheusMetricsExporterSample\n# TYPE timer_mean gauge\ntimer_mean{service=\"service_1\",server=\"server_1_1\",port=\"111\",} 1.000341504\ntimer_mean{service=\"service_1\",server=\"server_1_2\",port=\"121\",} 2.000683008\ntimer_mean{service=\"service_2\",server=\"server_2_1\",port=\"211\",} 2.9947330560000003\n# HELP timer_min Timer for PrometheusMetricsExporterSample\n# TYPE timer_min gauge\ntimer_min{service=\"service_1\",server=\"server_1_1\",port=\"111\",} 0.998244352\ntimer_min{service=\"service_1\",server=\"server_1_2\",port=\"121\",} 1.996488704\ntimer_min{service=\"service_2\",server=\"server_2_1\",port=\"211\",} 2.986344448\n```\n\n### ZabbixMetricsJsonExporter and ZabbixLldMetricsReporter\n\n```ZabbixMetricsJsonExporter``` exports metrics in the format that can be adapted for Zabbix.  \nThis is a non-standard format used in a number of RingCentral projects.    \n\n```ZabbixLldMetricsReporter``` exports MBeans that can be used for Zabbix low-level discovery  \n(https://www.zabbix.com/documentation/current/manual/discovery/low_level_discovery).  \n\nDependencies:\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.ringcentral.platform.metrics\u003c/groupId\u003e\n    \u003cartifactId\u003emetrics-facade-base\u003c/artifactId\u003e\n    \u003cversion\u003e4.2.0-RELEASE\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n```ZabbixMetricsJsonExporter``` and ```ZabbixLldMetricsReporter``` are best explained with:  \n```ZabbixReportersSample.java```\n```java\nMetricRegistry registry = new DefaultMetricRegistry();\nDefaultInstanceSampleSpecModsProvider miSampleSpecModsProvider = new DefaultInstanceSampleSpecModsProvider();\n\nmiSampleSpecModsProvider.addMod(\n    forMetricInstancesMatching(\n        nameMask(\"histogram.**\"),\n        instance -\u003e \"service_2\".equals(instance.valueOf(SERVICE))),\n    (metric, instance, currSpec) -\u003e instanceSampleSpec().disable());\n\nmiSampleSpecModsProvider.addMod(\n    forMetricWithName(\"histogram\"),\n    (metric, instance, currSpec) -\u003e instanceSampleSpec().name(instance.name().withNewPart(\"test\")));\n\nDefaultSampleSpecModsProvider sampleSpecModsProvider = new DefaultSampleSpecModsProvider();\n\nsampleSpecModsProvider.addMod(\n    forMetricInstancesMatching(\n        nameMask(\"histogram.**\"),\n        instance -\u003e instance instanceof HistogramInstance),\n    (instanceSampleSpec, instance, measurableValues, measurable, currSpec) -\u003e\n        measurable instanceof Max ? sampleSpec().disable() : sampleSpec());\n\nDefaultInstanceSamplesProvider miSamplesProvider = new DefaultInstanceSamplesProvider(\n    miSampleSpecModsProvider,\n    sampleSpecModsProvider,\n    new DefaultSampleSpecProvider(CustomMeasurableNameProvider.INSTANCE),\n    registry);\n\nZabbixMetricsJsonExporter exporter = new ZabbixMetricsJsonExporter(miSamplesProvider);\n\n// LLD\nZGroupMBeansExporter zGroupMBeansExporter = new ZGroupMBeansExporter(\n    \"zabbixReportersSample.zabbix.lld:type=\",\n    DefaultZGroupJsonMapper.INSTANCE,\n    \"JsonData\");\n\nzGroupMBeansExporter.ensureGroup(\"server\");\nZabbixLldMetricsReporter lldReporter = new ZabbixLldMetricsReporter(zGroupMBeansExporter);\n\nlldReporter.addRules(\n    forMetricInstancesMatching(nameMask(\"histogram.**\")),\n    new Rule(\n        \"service\",\n        List.of(new RuleItem(SERVICE, \"service\"), new RuleItem(SERVER, \"server\"))));\n\nlldReporter.addRules(\n    forMetricInstancesMatching(nameMask(\"histogram.**\")),\n    new Rule(\n        \"server\",\n        List.of(new RuleItem(i -\u003e i.valueOf(SERVICE) + \"/\" + i.valueOf(SERVER), \"server\"))));\n\nregistry.addListener(lldReporter);\n\n// Metrics\nHistogram h = registry.histogram(\n    withName(\"histogram\"),\n    () -\u003e withHistogram()\n        .labels(SERVICE, SERVER, PORT)\n        .measurables(COUNT, MAX, MEAN, Buckets.of(scale())));\n\nh.update(1, forLabelValues(SERVICE.value(\"service_1\"), SERVER.value(\"server_1_1\"), PORT.value(\"111\")));\nh.update(2, forLabelValues(SERVICE.value(\"service_1\"), SERVER.value(\"server_1_2\"), PORT.value(\"121\")));\nh.update(3, forLabelValues(SERVICE.value(\"service_2\"), SERVER.value(\"server_2_1\"), PORT.value(\"211\")));\n\n...\n\nstatic ScaleBuilder\u003c?\u003e scale() {\n    return\n        // 100 ms\n        first(linear().steps(25, MILLISECONDS, 4))\n        // 500 ms\n        .then(linear().steps(100, MILLISECONDS, 4).withInf());\n}\n```\n\n```exporter.exportMetrics()``` as JSON:  \n```json\n{\n  \"delta\": [\n    {\n      \"timer.test.count\": 3\n    },\n    {\n      \"timer.test.service_1.count\": 2\n    },\n    {\n      \"timer.test.service_1.server_1_1.111.count\": 1\n    },\n    {\n      \"timer.test.service_1.server_1_1.count\": 1\n    },\n    {\n      \"timer.test.service_1.server_1_2.121.count\": 1\n    },\n    {\n      \"timer.test.service_1.server_1_2.count\": 1\n    }\n  ],\n  \"instant\": [\n    {\n      \"timer.test.duration.0ms_bucket\": 0\n    },\n    {\n      \"timer.test.duration.100ms_bucket\": 3\n    },\n    {\n      \"timer.test.duration.200ms_bucket\": 3\n    },\n    {\n      \"timer.test.duration.25ms_bucket\": 3\n    },\n    {\n      \"timer.test.duration.300ms_bucket\": 3\n    },\n    {\n      \"timer.test.duration.400ms_bucket\": 3\n    },\n    {\n      \"timer.test.duration.500ms_bucket\": 3\n    },\n    {\n      \"timer.test.duration.50ms_bucket\": 3\n    },\n    {\n      \"timer.test.duration.75ms_bucket\": 3\n    },\n    {\n      \"timer.test.duration.inf_bucket\": 3\n    },\n    {\n      \"timer.test.duration.mean\": 2.0E-6\n    },\n    {\n      \"timer.test.service_1.duration.0ms_bucket\": 0\n    },\n    {\n      \"timer.test.service_1.duration.100ms_bucket\": 2\n    },\n    {\n      \"timer.test.service_1.duration.200ms_bucket\": 2\n    },\n    {\n      \"timer.test.service_1.duration.25ms_bucket\": 2\n    },\n    {\n      \"timer.test.service_1.duration.300ms_bucket\": 2\n    },\n    {\n      \"timer.test.service_1.duration.400ms_bucket\": 2\n    },\n    {\n      \"timer.test.service_1.duration.500ms_bucket\": 2\n    },\n    {\n      \"timer.test.service_1.duration.50ms_bucket\": 2\n    },\n    {\n      \"timer.test.service_1.duration.75ms_bucket\": 2\n    },\n    {\n      \"timer.test.service_1.duration.inf_bucket\": 2\n    },\n    {\n      \"timer.test.service_1.duration.mean\": 1.5E-6\n    },\n    {\n      \"timer.test.service_1.server_1_1.111.duration.0ms_bucket\": 0\n    },\n    {\n      \"timer.test.service_1.server_1_1.111.duration.100ms_bucket\": 1\n    },\n    {\n      \"timer.test.service_1.server_1_1.111.duration.200ms_bucket\": 1\n    },\n    {\n      \"timer.test.service_1.server_1_1.111.duration.25ms_bucket\": 1\n    },\n    {\n      \"timer.test.service_1.server_1_1.111.duration.300ms_bucket\": 1\n    },\n    {\n      \"timer.test.service_1.server_1_1.111.duration.400ms_bucket\": 1\n    },\n    {\n      \"timer.test.service_1.server_1_1.111.duration.500ms_bucket\": 1\n    },\n    {\n      \"timer.test.service_1.server_1_1.111.duration.50ms_bucket\": 1\n    },\n    {\n      \"timer.test.service_1.server_1_1.111.duration.75ms_bucket\": 1\n    },\n    {\n      \"timer.test.service_1.server_1_1.111.duration.inf_bucket\": 1\n    },\n    {\n      \"timer.test.service_1.server_1_1.111.duration.mean\": 1.0E-6\n    },\n    {\n      \"timer.test.service_1.server_1_1.duration.0ms_bucket\": 0\n    },\n    {\n      \"timer.test.service_1.server_1_1.duration.100ms_bucket\": 1\n    },\n    {\n      \"timer.test.service_1.server_1_1.duration.200ms_bucket\": 1\n    },\n    {\n      \"timer.test.service_1.server_1_1.duration.25ms_bucket\": 1\n    },\n    {\n      \"timer.test.service_1.server_1_1.duration.300ms_bucket\": 1\n    },\n    {\n      \"timer.test.service_1.server_1_1.duration.400ms_bucket\": 1\n    },\n    {\n      \"timer.test.service_1.server_1_1.duration.500ms_bucket\": 1\n    },\n    {\n      \"timer.test.service_1.server_1_1.duration.50ms_bucket\": 1\n    },\n    {\n      \"timer.test.service_1.server_1_1.duration.75ms_bucket\": 1\n    },\n    {\n      \"timer.test.service_1.server_1_1.duration.inf_bucket\": 1\n    },\n    {\n      \"timer.test.service_1.server_1_1.duration.mean\": 1.0E-6\n    },\n    {\n      \"timer.test.service_1.server_1_2.121.duration.0ms_bucket\": 0\n    },\n    {\n      \"timer.test.service_1.server_1_2.121.duration.100ms_bucket\": 1\n    },\n    {\n      \"timer.test.service_1.server_1_2.121.duration.200ms_bucket\": 1\n    },\n    {\n      \"timer.test.service_1.server_1_2.121.duration.25ms_bucket\": 1\n    },\n    {\n      \"timer.test.service_1.server_1_2.121.duration.300ms_bucket\": 1\n    },\n    {\n      \"timer.test.service_1.server_1_2.121.duration.400ms_bucket\": 1\n    },\n    {\n      \"timer.test.service_1.server_1_2.121.duration.500ms_bucket\": 1\n    },\n    {\n      \"timer.test.service_1.server_1_2.121.duration.50ms_bucket\": 1\n    },\n    {\n      \"timer.test.service_1.server_1_2.121.duration.75ms_bucket\": 1\n    },\n    {\n      \"timer.test.service_1.server_1_2.121.duration.inf_bucket\": 1\n    },\n    {\n      \"timer.test.service_1.server_1_2.121.duration.mean\": 2.0E-6\n    },\n    {\n      \"timer.test.service_1.server_1_2.duration.0ms_bucket\": 0\n    },\n    {\n      \"timer.test.service_1.server_1_2.duration.100ms_bucket\": 1\n    },\n    {\n      \"timer.test.service_1.server_1_2.duration.200ms_bucket\": 1\n    },\n    {\n      \"timer.test.service_1.server_1_2.duration.25ms_bucket\": 1\n    },\n    {\n      \"timer.test.service_1.server_1_2.duration.300ms_bucket\": 1\n    },\n    {\n      \"timer.test.service_1.server_1_2.duration.400ms_bucket\": 1\n    },\n    {\n      \"timer.test.service_1.server_1_2.duration.500ms_bucket\": 1\n    },\n    {\n      \"timer.test.service_1.server_1_2.duration.50ms_bucket\": 1\n    },\n    {\n      \"timer.test.service_1.server_1_2.duration.75ms_bucket\": 1\n    },\n    {\n      \"timer.test.service_1.server_1_2.duration.inf_bucket\": 1\n    },\n    {\n      \"timer.test.service_1.server_1_2.duration.mean\": 2.0E-6\n    }\n  ]\n}\n```\n\nJMX MBean attribute ```zabbixReportersSample.zabbix.lld:type=service.JsonData```:\n```json\n{\n  \"data\": [\n    {\n      \"{#SERVICE}\": \"service_1\",\n      \"{#SERVER}\": \"server_1_1\"\n    },\n    {\n      \"{#SERVICE}\": \"service_1\",\n      \"{#SERVER}\": \"server_1_2\"\n    },\n    {\n      \"{#SERVICE}\": \"service_2\",\n      \"{#SERVER}\": \"server_2_1\"\n    }\n  ]\n}\n```\n\nJMX MBean attribute ```zabbixReportersSample.zabbix.lld:type=server.JsonData```:\n```json\n{\n  \"data\": [\n    {\n      \"{#SERVER}\": \"service_1/server_1_1\"\n    },\n    {\n      \"{#SERVER}\": \"service_1/server_1_2\"\n    },\n    {\n      \"{#SERVER}\": \"service_2/server_2_1\"\n    }\n  ]\n}\n```\n\n### TelegrafMetricsJsonExporter\n\n```TelegrafMetricsJsonExporter``` exports metrics in the Telegraf format (https://github.com/influxdata/telegraf).\n\nDependencies:\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.ringcentral.platform.metrics\u003c/groupId\u003e\n    \u003cartifactId\u003emetrics-facade-base\u003c/artifactId\u003e\n    \u003cversion\u003e4.2.0-RELEASE\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n```TelegrafMetricsJsonExporter``` is best explained with:  \n```TelegrafMetricsJsonExporterSample.java```\n```java\nMetricRegistry registry = new DefaultMetricRegistry();\nDefaultInstanceSampleSpecModsProvider miSampleSpecModsProvider = new DefaultInstanceSampleSpecModsProvider();\n\nmiSampleSpecModsProvider.addMod(\n    forMetricInstancesMatching(\n        nameMask(\"histogram.**\"),\n        instance -\u003e \"service_2\".equals(instance.valueOf(SERVICE))),\n    (metric, instance, currSpec) -\u003e instanceSampleSpec().disable());\n\nmiSampleSpecModsProvider.addMod(\n    forMetricWithName(\"histogram\"),\n    (metric, instance, currSpec) -\u003e instanceSampleSpec().name(instance.name().withNewPart(\"test\")));\n\nDefaultSampleSpecModsProvider sampleSpecModsProvider = new DefaultSampleSpecModsProvider();\n\nsampleSpecModsProvider.addMod(\n    forMetricInstancesMatching(\n        nameMask(\"histogram.**\"),\n        instance -\u003e instance instanceof HistogramInstance),\n    (instanceSampleSpec, instance, measurableValues, measurable, currSpec) -\u003e\n        measurable instanceof Max ? sampleSpec().disable() : sampleSpec());\n\nDefaultInstanceSamplesProvider miSamplesProvider = new DefaultInstanceSamplesProvider(\n    miSampleSpecModsProvider,\n    sampleSpecModsProvider,\n    new DefaultSampleSpecProvider(CustomMeasurableNameProvider.INSTANCE),\n    registry);\n\n// Metrics\nHistogram h = registry.histogram(\n    withName(\"histogram\"),\n    () -\u003e withHistogram()\n        .labels(SERVICE, SERVER, PORT)\n        .measurables(COUNT, MAX, MEAN));\n\nh.update(1, forLabelValues(SERVICE.value(\"service_1\"), SERVER.value(\"server_1_1\"), PORT.value(\"111\")));\nh.update(2, forLabelValues(SERVICE.value(\"service_1\"), SERVER.value(\"server_1_2\"), PORT.value(\"121\")));\nh.update(3, forLabelValues(SERVICE.value(\"service_2\"), SERVER.value(\"server_2_1\"), PORT.value(\"211\")));\n```\n\n```exporter.exportMetrics()``` as JSON (without grouping by types):\n```json\n{\n  \"histogram.test.mean\": 2.0,\n  \"histogram.test.count\": 3,\n  \"histogram.test.service_1.server_1_1.111.mean\": 1.0,\n  \"histogram.test.service_1.server_1_1.111.count\": 1,\n  \"histogram.test.service_1.server_1_2.121.mean\": 2.0,\n  \"histogram.test.service_1.server_1_2.121.count\": 1,\n  \"histogram.test.service_1.mean\": 1.5,\n  \"histogram.test.service_1.count\": 2,\n  \"histogram.test.service_1.server_1_2.mean\": 2.0,\n  \"histogram.test.service_1.server_1_2.count\": 1,\n  \"histogram.test.service_1.server_1_1.mean\": 1.0,\n  \"histogram.test.service_1.server_1_1.count\": 1\n}\n```\n\n```exporter.exportMetrics()``` as JSON (with grouping by types - a non-standard format):\n```json\n{\n  \"instant\": {\n    \"histogram.test.mean\": 2.0,\n    \"histogram.test.service_1.server_1_1.111.mean\": 1.0,\n    \"histogram.test.service_1.server_1_2.121.mean\": 2.0,\n    \"histogram.test.service_1.mean\": 1.5,\n    \"histogram.test.service_1.server_1_2.mean\": 2.0,\n    \"histogram.test.service_1.server_1_1.mean\": 1.0\n  },\n  \"delta\": {\n    \"histogram.test.count\": 3,\n    \"histogram.test.service_1.server_1_1.111.count\": 1,\n    \"histogram.test.service_1.server_1_2.121.count\": 1,\n    \"histogram.test.service_1.count\": 2,\n    \"histogram.test.service_1.server_1_2.count\": 1,\n    \"histogram.test.service_1.server_1_1.count\": 1\n  }\n}\n```\n\n### JmxMetricsReporter\n\n```JmxMetricsReporter``` exports MBeans for the corresponding metric instances.  \n\nDependencies:\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.ringcentral.platform.metrics\u003c/groupId\u003e\n    \u003cartifactId\u003emetrics-facade-base\u003c/artifactId\u003e\n    \u003cversion\u003e4.2.0-RELEASE\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n```JmxMetricsReporter``` is best explained with:  \n```JmxMetricsReporterSample.java```\n```java\nMetricRegistry registry = new DefaultMetricRegistry();\n\n// Default config\n// registry.addListener(new JmxMetricsReporter());\n\nMaskTreeMetricNamedInfoProvider\u003cMBeanSpecProvider\u003e mBeanSpecs = new MaskTreeMetricNamedInfoProvider\u003c\u003e();\n\nmBeanSpecs.addInfo(\n    forMetricInstancesMatching(\n        nameMask(\"rate.**\"),\n        instance -\u003e \"service_2\".equals(instance.valueOf(SERVICE))),\n    instance -\u003e mBeanSpec().disable());\n\nmBeanSpecs.addInfo(\n    forMetricsWithNamePrefix(\"rate\"),\n    instance -\u003e mBeanSpec()\n        .name(\n            instance.isTotalInstance() ?\n            instance.name() :\n            instance.name().withNewPart(instance.valueOf(SERVICE)))\n        .labelValues(instance.labelValuesWithout(SERVICE)));\n\nJmxMetricsReporter jmxReporter = new JmxMetricsReporter(\n    mBeanSpecs,\n    getPlatformMBeanServer(),\n    new DefaultObjectNameProvider(),\n    new CustomMeasurableNameProvider(),\n    \"JmxMetricsReporterSample\");\n\nregistry.addListener(jmxReporter);\n\nRate r = registry.rate(\n    withName(\"rate\"),\n    () -\u003e withRate()\n        .labels(SERVICE, SERVER, PORT)\n        .measurables(COUNT, MEAN_RATE, ONE_MINUTE_RATE));\n\nr.mark(1, forLabelValues(SERVICE.value(\"service_1\"), SERVER.value(\"server_1_1\"), PORT.value(\"111\")));\nr.mark(2, forLabelValues(SERVICE.value(\"service_1\"), SERVER.value(\"server_1_2\"), PORT.value(\"121\")));\nr.mark(3, forLabelValues(SERVICE.value(\"service_2\"), SERVER.value(\"server_2_1\"), PORT.value(\"211\")));\n```\n\nJMX MBean attribute ```JmxMetricsReporterSample:name=rate.service_1,server=server_1_2,port=121.count = 2```\n\n## Metrics Producers\n\n***Metric producer*** *adds some predefined metrics to a registry*.    \nMetrics producers are represented by subclasses of ```MetricsProducer```.   \n\n```MetricsProducersSample.java```  \n```java\nMetricRegistry registry = new DefaultMetricRegistry();\n\n// adds some system metrics\nnew SystemMetricsProducer().produceMetrics(registry);\n```\n\n### SystemMetricsProducer\n\n```SystemMetricsProducer``` just combines:\n- ```RuntimeMetricsProducer```\n- ```OperatingSystemMetricsProducer```\n- ```GarbageCollectorsMetricsProducer```\n- ```MemoryMetricsProducer```\n- ```ThreadsMetricsProducer```\n- ```BufferPoolsMetricsProducer```\n- ```ClassesMetricsProducer```\n\n### RuntimeMetricsProducer\n\nAdds a number of metrics related to the JVM.\u003cbr\u003e\nSee [RuntimeMetricsProducer](metrics-facade-base/src/main/java/com/ringcentral/platform/metrics/producers/RuntimeMetricsProducer.java) for details.\u003cbr\u003e\nIt is based on ```java.lang.management.RuntimeMXBean```.\n\n### OperatingSystemMetricsProducer\n\nAdds a number of metrics related to operating system:\nOS name, OS architecture, CPU time used by the process, etc.\u003cbr\u003e\nSee [DefaultOperatingSystemMetricsProducer](metrics-facade-base/src/main/java/com/ringcentral/platform/metrics/producers/nonlabeled/DefaultOperatingSystemMetricsProducer.java) and [LabeledOperatingSystemMetricsProducer](metrics-facade-base/src/main/java/com/ringcentral/platform/metrics/producers/labeled/LabeledOperatingSystemMetricsProducer.java) for details.\u003cbr\u003eIt is based on ```com.sun.management.OperatingSystemMXBean```.  \n\n### GarbageCollectorsMetricsProducer\n\nAdds a number of metrics related to garbage collection:        \nthe total number of collections that have occurred, the approximate accumulated collection elapsed time, etc.\u003cbr\u003e\nSee [DefaultGarbageCollectorsMetricsProducer](metrics-facade-base/src/main/java/com/ringcentral/platform/metrics/producers/nonlabeled/DefaultGarbageCollectorsMetricsProducer.java) and [LabeledGarbageCollectorsMetricsProducer](metrics-facade-base/src/main/java/com/ringcentral/platform/metrics/producers/labeled/LabeledGarbageCollectorsMetricsProducer.java) for details.\u003cbr\u003e It is based on ```java.lang.management.GarbageCollectorMetricSet```.      \n\n### MemoryMetricsProducer\n\nAdds a number of metrics related to memory:  \nheap memory usage, non-heap memory usage, etc.\u003cbr\u003e\nSee [DefaultMemoryMetricsProducer](metrics-facade-base/src/main/java/com/ringcentral/platform/metrics/producers/nonlabeled/DefaultMemoryMetricsProducer.java) and [LabeledMemoryMetricsProducer](metrics-facade-base/src/main/java/com/ringcentral/platform/metrics/producers/labeled/LabeledMemoryMetricsProducer.java) for details.\u003cbr\u003e It is based on ```java.lang.management.MemoryMXBean```.    \n\n### ThreadsMetricsProducer\n\nAdds a number of metrics related to threads:    \nthe current number of live threads, the total number of threads created and also started since the JVM started, etc.\u003cbr\u003e\nSee [DefaultThreadsMetricsProducer](metrics-facade-base/src/main/java/com/ringcentral/platform/metrics/producers/nonlabeled/DefaultThreadsMetricsProducer.java) and [LabeledThreadsMetricsProducer](metrics-facade-base/src/main/java/com/ringcentral/platform/metrics/producers/labeled/LabeledThreadsMetricsProducer.java) for details.\u003cbr\u003e It is based on ```java.lang.management.ThreadMXBean```      \n\n### BufferPoolsMetricsProducer\n\nAdds a number of metrics related to buffer pools.\u003cbr\u003e\nSee [DefaultBufferPoolsMetricsProducer](metrics-facade-base/src/main/java/com/ringcentral/platform/metrics/producers/nonlabeled/DefaultBufferPoolsMetricsProducer.java) and [LabeledBufferPoolsMetricsProducer](metrics-facade-base/src/main/java/com/ringcentral/platform/metrics/producers/labeled/LabeledBufferPoolsMetricsProducer.java) for details.\u003cbr\u003e It is based on the MBeans ```java.nio:type=BufferPool,name=\u003cpool_name\u003e```.      \n\n### ClassesMetricsProducer\n\nAdds a number of metrics related to the class loading system of the JVM.\nSee [ClassesMetricsProducer](metrics-facade-base/src/main/java/com/ringcentral/platform/metrics/producers/ClassesMetricsProducer.java) for details.\u003cbr\u003e\nIt is based on ```java.lang.management.ClassLoadingMXBean```.\n\n## Integration\n\n### Dropwizard MetricRegistry integration\n\n#### Export using DropwizardMetricRegistryDefaultInstanceSamplesProvider\n\n`DropwizardMetricRegistryDefaultInstanceSamplesProvider` helps to export metrics from existing `com.codahale.metrics.MetricRegistry` using [Metrics Reporters](#metrics-reporters) (except PrometheusMetricsExporter).\n\nFor example,\n```java\nMetricRegistry registry = new MetricRegistry();\n\nAtomicInteger g1 = new AtomicInteger();\nregistry.gauge(\"g1\", () -\u003e new Gauge\u003cInteger\u003e() {\n  @Override\n  public Integer getValue() {\n    return g1.incrementAndGet();\n  }\n});\n\nCounter c1 = registry.counter(\"c1\");\nc1.inc();\n\nHistogram h1 = registry.histogram(\"h1\");\nh1.update(10);\nh1.update(100);\nh1.update(1000);\n\nTimer t1 = registry.timer(\"t1\");\nt1.update(Duration.ofMinutes(10));\n\nMeter m1 = registry.meter(\"m1\");\nm1.mark();\nm1.mark(10);\n\nDropwizardMetricRegistryDefaultInstanceSamplesProvider provider = new DropwizardMetricRegistryDefaultInstanceSamplesProvider(registry);\n\nTelegrafMetricsJsonExporter telegrafMetricsJsonExporter = new TelegrafMetricsJsonExporter(true, provider);\nMetricsJson metrics = telegrafMetricsJsonExporter.exportMetrics();\n\nObjectMapper mapper = new ObjectMapper();\nSystem.out.println(mapper.writeValueAsString(metrics));\n```\nOutput:\n```json\n{\"instant\":{\"g1\":1.0,\"h1.mean\":370.0,\"h1.max\":1000,\"h1.min\":10,\"h1.median\":100.0,\"h1.std_dev\":446.9899327725402,\"h1.75_percentile\":1000.0,\"h1.95_percentile\":1000.0,\"h1.98_percentile\":1000.0,\"h1.99_percentile\":1000.0,\"h1.999_percentile\":1000.0,\"t1.mean\":600.0,\"t1.max\":600.0,\"t1.min\":600.0,\"t1.median\":600.0,\"t1.std_dev\":0.0,\"t1.75_percentile\":600.0,\"t1.95_percentile\":600.0,\"t1.98_percentile\":600.0,\"t1.99_percentile\":600.0,\"t1.999_percentile\":600.0,\"m1.1_minute_rate\":0.0,\"m1.5_minute_rate\":0.0,\"m1.15_minute_rate\":0.0,\"m1.mean_rate\":288.9463950588065},\"delta\":{\"c1\":1,\"h1.count\":3,\"t1.count\":1,\"m1.total\":11}}\n```\nRequired dependency:\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003ecom.ringcentral.platform.metrics\u003c/groupId\u003e\n  \u003cartifactId\u003emetrics-facade-dropwizard\u003c/artifactId\u003e\n  \u003cversion\u003e4.2.0-RELEASE\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n#### Export using DropwizardMetricRegistryPrometheusInstanceSamplesProvider\n\n`DropwizardMetricRegistryPrometheusInstanceSamplesProvider` helps to export metrics from existing `com.codahale.metrics.MetricRegistry` using PrometheusMetricsExporter.\n\nFor example,\n```java\nMetricRegistry registry = new MetricRegistry();\n\nAtomicInteger g1 = new AtomicInteger();\nregistry.gauge(\"g1\", () -\u003e new Gauge\u003cInteger\u003e() {\n  @Override\n  public Integer getValue() {\n    return g1.incrementAndGet();\n  }\n});\n\nCounter c1 = registry.counter(\"c1\");\nc1.inc();\n\nHistogram h1 = registry.histogram(\"h1\");\nh1.update(10);\nh1.update(100);\nh1.update(1000);\n\nTimer t1 = registry.timer(\"t1\");\nt1.update(Duration.ofMinutes(10));\n\nMeter m1 = registry.meter(\"m1\");\nm1.mark();\nm1.mark(10);\n\nDropwizardMetricRegistryDefaultInstanceSamplesProvider provider = new DropwizardMetricRegistryDefaultInstanceSamplesProvider(registry);\n\nTelegrafMetricsJsonExporter telegrafMetricsJsonExporter = new TelegrafMetricsJsonExporter(true, provider);\nMetricsJson metrics = telegrafMetricsJsonExporter.exportMetrics();\n\nSystem.out.println(metrics);\n```\nOutput:\n```bash\n# HELP h1 Generated from Dropwizard metric import (metric=h1, type=com.codahale.metrics.Histogram)\n# TYPE h1 summary\nh1{quantile=\"0.5\",} 100.0\nh1{quantile=\"0.75\",} 1000.0\nh1{quantile=\"0.95\",} 1000.0\nh1{quantile=\"0.98\",} 1000.0\nh1{quantile=\"0.99\",} 1000.0\nh1{quantile=\"0.999\",} 1000.0\nh1_count 3.0\n# HELP g1 Generated from Dropwizard metric import (metric=g1, type=com.ringcentral.platform.metrics.samples.temp.DropwizardMetricRegistryPrometheusInstanceSamplesProviderSample$1)\n# TYPE g1 gauge\ng1 0.0\n# HELP t1 Generated from Dropwizard metric import (metric=t1, type=com.codahale.metrics.Timer)\n# TYPE t1 summary\nt1{quantile=\"0.5\",} 600.0\nt1{quantile=\"0.75\",} 600.0\nt1{quantile=\"0.95\",} 600.0\nt1{quantile=\"0.98\",} 600.0\nt1{quantile=\"0.99\",} 600.0\nt1{quantile=\"0.999\",} 600.0\nt1_count 1.0\n# HELP c1 Generated from Dropwizard metric import (metric=c1, type=com.codahale.metrics.Counter)\n# TYPE c1 gauge\nc1 1.0\n```\n\nRequired dependency:\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003ecom.ringcentral.platform.metrics\u003c/groupId\u003e\n  \u003cartifactId\u003emetrics-facade-dropwizard-to-prometheus\u003c/artifactId\u003e\n  \u003cversion\u003e4.2.0-RELEASE\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n## License\n\nMIT    ","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fringcentral%2Fmetrics-facade","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fringcentral%2Fmetrics-facade","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fringcentral%2Fmetrics-facade/lists"}