{"id":24897139,"url":"https://github.com/eiiches/scriptable-jmx-exporter","last_synced_at":"2025-10-16T11:31:21.093Z","repository":{"id":39760264,"uuid":"146200958","full_name":"eiiches/scriptable-jmx-exporter","owner":"eiiches","description":"A javaagent for scraping and exposing MBeans to Prometheus","archived":false,"fork":false,"pushed_at":"2024-03-04T17:06:11.000Z","size":857,"stargazers_count":7,"open_issues_count":18,"forks_count":2,"subscribers_count":0,"default_branch":"develop","last_synced_at":"2025-07-29T23:50:12.279Z","etag":null,"topics":["java","java-agent","jmx","monitoring","prometheus","prometheus-exporter"],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/eiiches.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}},"created_at":"2018-08-26T17:18:46.000Z","updated_at":"2024-01-12T09:09:58.000Z","dependencies_parsed_at":"2023-12-18T09:51:30.696Z","dependency_job_id":"dab14453-37ad-4178-86d6-bb37061d3985","html_url":"https://github.com/eiiches/scriptable-jmx-exporter","commit_stats":null,"previous_names":["eiiches/java-prometheus-metrics-agent"],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/eiiches/scriptable-jmx-exporter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eiiches%2Fscriptable-jmx-exporter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eiiches%2Fscriptable-jmx-exporter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eiiches%2Fscriptable-jmx-exporter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eiiches%2Fscriptable-jmx-exporter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eiiches","download_url":"https://codeload.github.com/eiiches/scriptable-jmx-exporter/tar.gz/refs/heads/develop","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eiiches%2Fscriptable-jmx-exporter/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279183675,"owners_count":26121446,"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-10-16T02:00:06.019Z","response_time":53,"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":["java","java-agent","jmx","monitoring","prometheus","prometheus-exporter"],"created_at":"2025-02-01T20:16:37.060Z","updated_at":"2025-10-16T11:31:20.485Z","avatar_url":"https://github.com/eiiches.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"*If you are reading this on `develop` branch, some of the features may not be present yet on the released versions.*\n\nScriptable JMX Exporter\n=======================\n\nJava agent to scrape and expose MBeans to Prometheus. Formerly, java-prometheus-metrics-agent.\n\n[![GitHub Actions](https://github.com/eiiches/scriptable-jmx-exporter/workflows/test/badge.svg)](https://github.com/eiiches/scriptable-jmx-exporter/actions)\n\nFeatures\n--------\n\n- Easy configuration. Defining a few generic rules should be enough for most users.\n  - MBeans attributes can be pattern matched by straightforward ObjectName-aware Regex. E.g.\n    - `java.*`\n    - `java.lang:type=OperatingSystem|Threading`\n    - `java.lang:type=GarbageCollector:LastGcInfo` matches regardless of `name=` key property.\n    - `foo:type=A,name=B` is equivalent to `foo:name=B,type=A`.\n  - All non-textual attributes from all MBeans are exposed by default.\n- Scripting in Java, which enables powerful customization. E.g.\n  - Converting a textual attribute to a numeric value (normal metric) or metric label with value 1 (info-style metric).\n  - Decomposing complex MBean name into metric labels.\n- Performance. Goal is to enable a large number of metrics (~50k) at shorter intervals (\u003e1s) without impacting workloads.\n  - See our [benchmark](#benchmark).\n\n\n#### Why another exporter? There's a bunch of exporters and there's even the official one.\n\nI needed something that can scrape many MBeans with a small number of rules. Writing a regex for each set of *key properties* (key=value,... part of MBean name) was impossibly hard, especially when\n*key properties* doesn't always have a consistent order depending on how it is constructed (because it's just a hash table).\n\n\n#### Requirements\n\n* Java 8 or newer\n\n\nQuick Start\n------------\n\n*If you don't want to run the agent now, download [scriptable-jmx-exporter-1.0.0-alpha5.jar](https://repo1.maven.org/maven2/net/thisptr/scriptable-jmx-exporter/1.0.0-alpha5/scriptable-jmx-exporter-1.0.0-alpha5.jar) and skip to [Usage](#usage).*\n\nYou can quickly try out this exporter by copy-and-pasting the following snippet to your shell (or by manually running one by one).\nThis will download the agent jar and a default configuration file, and then start the exporter using `-javaagent` option.\n\n```sh\n# Download the agent jar and a default configuration file.\ncurl -LO https://repo1.maven.org/maven2/net/thisptr/scriptable-jmx-exporter/1.0.0-alpha5/scriptable-jmx-exporter-1.0.0-alpha5.jar\ncurl -LO https://raw.githubusercontent.com/eiiches/scriptable-jmx-exporter/v1.0.0-alpha5/src/main/resources/scriptable-jmx-exporter.yaml\n\n# Finally, run JVM with the exporter enabled.\njava -javaagent:scriptable-jmx-exporter-1.0.0-alpha5.jar=@scriptable-jmx-exporter.yaml net.thisptr.jmx.exporter.tools.Pause\n```\n\nNow, open [http://localhost:9639/metrics](http://localhost:9639/metrics) in your browser to see the exposed metrics.\n\nThe next step is to replace the Pause program with your favorite application that you want to monitor.\nContinue reading or alternatively you can check out real-world [examples](examples) to learn how to customize the exporter.\n\n\nUsage\n-----\n\nAdd `-javaagent` option to JVM arguments.\n\n```sh\n# This starts an exporter without an explicit configuration file.\n# The default configuration from src/main/resources/scriptable-jmx-exporter.yaml is used.\njava -javaagent:\u003cPATH_TO_AGENT_JAR\u003e ...\n```\n\nConfigurations can be passed as a javaagent argument. See Configuration section for details.\n\n```sh\n# Set configurations in JSON directly on command line (YAML is not supported here)\njava -javaagent:\u003cPATH_TO_AGENT_JAR\u003e=\u003cCONFIG_JSON\u003e ...\n\n# e.g.\n# java -javaagent:scriptable-jmx-exporter-1.0.0-alpha5.jar='{\"rules\":[{\"pattern\":[\"com.sun.management:type=HotSpotDiagnostic:DiagnosticOptions\",\"java.lang:type=Threading:AllThreadIds\",\"jdk.management.jfr\"],\"skip\":true},{\"transform\":\"!java V1.transform(in, out, \\\"type\\\")\"}]}' ...\n\n# ---\n# Load configurations from PATH_TO_CONFIG_YAML file\njava -javaagent:\u003cPATH_TO_AGENT_JAR\u003e=@\u003cPATH_TO_CONFIG_YAML\u003e ...\n\n# e.g.\n# java -javaagent:scriptable-jmx-exporter-1.0.0-alpha5.jar=@/etc/foo.yaml ...\n# java -javaagent:scriptable-jmx-exporter-1.0.0-alpha5.jar=@foo.yaml ...\n# java -javaagent:scriptable-jmx-exporter-1.0.0-alpha5.jar=@classpath:foo.yaml ...\n```\n\nIf multiple comma-separated configurations are specified, former configurations are overriden by (or merged with) the latter ones.\n\n```sh\njava -javaagent:\u003cPATH_TO_AGENT_JAR\u003e=@\u003cPATH_TO_CONFIG_YAML\u003e,\u003cCONFIG_JSON\u003e ...\n\n# e.g.\n# java -javaagent:scriptable-jmx-exporter-1.0.0-alpha5.jar=@/etc/foo.yaml,'{\"server\":{\"bind_address\":\":19639\"}}' ...\n```\n\nConfiguration\n-------------\n\n*This section requires a basic grasp of data models used in Java Management Extensions (JMX).\nIf you are new to this area and don't understand what ObjectName or MBean is, I strongly recommend you to read [Java Management Extensions (JMX) Best Practices](https://www.oracle.com/java/technologies/javase/management-extensions-best-practices.html) first.*\n\n### Automatic Reloading\n\nConfigurations are automatically reloaded whenever the file (`\u003cPATH_TO_CONFIG_YAML\u003e` in the description above) is modified. This behavior cannot be turned off (at least for now).\n\nSo, whenever you need to write a new configuration, it's easier to start with a simple configuration (e.g. [scriptable-jmx-exporter.yaml](https://github.com/eiiches/scriptable-jmx-exporter/blob/develop/src/main/resources/scriptable-jmx-exporter.yaml) which is the default configuration picked when no configuration is provided on command line) and incrementally edit the configuration file while actually running your software.\n\nIf the exporter fails to load a new configuration, most likely due to configuration error, the exporter will continue to use the previous configuration. On the contrary, application startup will fail if the configuration has any errors.\nIt's generally considered safe (in a sense that it will not interrupt running workloads) to reconfigure the exporter on a production cluster while they are running.\n\n### Example\n\n```yaml\n# You can omit `server` and `options` if you are happy with the default values\nserver:\n  bind_address: '0.0.0.0:9639' # default\noptions:\n  include_timestamp: true # Include scraping timestamp for each metrics (default).\n  include_type: true # Enable TYPE comments (default).\n  include_help: true # Enable HELP comments (default).\ndeclarations: |\n  public static void foo() {\n    log(\"foo\");\n  }\nrules:\n- pattern:\n  # Drop less useful attributes JVM exposes.\n  - 'com\\\\.sun\\\\.management:type=HotSpotDiagnostic:DiagnosticOptions'\n  - 'java\\\\.lang:type=Threading:AllThreadIds'\n  - 'jdk\\\\.management\\\\.jfr'\n  # Some instrumentation libraries (such as Dropwizard Metrics) expose pre-calculated rate statistics.\n  # Since Prometheus can calculate these values by itself, we don't need them. Skip.\n  - '::.*MinuteRate'\n  - '::MeanRate'\n  skip: true\n# Rule for known MBeans.\n- pattern: 'java\\\\.lang|java\\\\.nio|jboss\\\\.threads|net\\\\.thisptr\\\\.jmx\\\\.exporter\\\\.agent.*'\n  transform: |\n    V1.transform(in, out, \"type\");\n# Default rule to cover the rest.\n- transform: |\n    V1.transform(in, out, \"type\");\n```\n\nThis YAML is mapped to [Config](src/main/java/net/thisptr/jmx/exporter/agent/config/Config.java) class using Jackson data-binding and validated by Hibernate validator.\n\nSee [examples](examples) directory for real-world examples.\n\n### Server Configuration\n\n| Key | Default | Description |\n|-|-|-|\n| `server.bind_address` | `0.0.0.0:9639` | IP and port to listen and servce metrics on. |\n\n### Handler Options\n\n| Key | Default | Description |\n|-|-|-|\n| `options.include_timestamp` | `true` | Specifies whether /metrics response should include a timestamp at which the metric is scraped. |\n| `options.include_help` | `true` | Enables HELP comment. |\n| `options.include_type` | `true` | Enables TYPE comment. |\n| `options.minimum_response_time` | `0` | A minimum time in milliseconds which every /metrics requests should take. This is used to avoid CPU spikes when there are thousands of metrics. When set, `options.include_timestamp` should not be disabled because the time at which a response completes differs from the time at which the metrics are scraped. |\n\nThese options can be overridden by URL parameters. E.g. `/metrics?minimum_response_time=1000`.\n\n### Declarations\n\nYou can define static classes and methods for use in transform scripts, condition expressions, etc. They will be automatically imported and available so you don't have to manually write `import` statements.\nMake sure to add `public static` in the declarations; otherwise, the classes and methods won't be accessible.\n\n```yaml\ndeclarations: |\n  import java.util.Map;\n\n  public static void foo() {\n    log(\"foo\");\n  }\n\n  public static class Foo {\n    // ...\n  }\n```\n\n### Rule Configuration\n\nRules are searched in order and a first match is used for each attribute.\n\n| Key | Default | Description |\n|-|-|-|\n| `rules[].pattern` | `null` | A pattern used to match MBean attributes this rule applies to. A rule with a `null` pattern applies to any attributes. See [Pattern Matching](#pattern-matching) for syntax details. |\n| `rules[].condition` | `true` | If an expression is set, this rule is used only when the expression evaluates to true. This is useful if you want to match an MBean attribute other than by its name, such as by its class name, etc. See [Condition Expression](#condition-expression) for details. |\n| `rules[].skip` | `false` | If `true`, skip exposition of the attribute to Prometheus. |\n| `rules[].transform` | `V1.transform(in, out, \"type\")` | A script to convert an MBean attribute to Prometheus metrics. See [Scripting](#scripting) for details. |\n\n#### Pattern Matching\n\nYou can use pattern matching to efficiently filter MBeans and their attributes. The general syntax is as follows:\n\n\u003e DOMAIN_REGEX`:`KEY_REGEX_1`=`VALUE_REGEX_1`,`...`:`ATTRIBUTE_REGEX\n\nThe last two parts separated by `:` can be omitted.\n\nExamples\n* `jdk\\.management\\.jfr` matches all MBeans within `jdk.management.jfr` domain.\n* `kafka:type=kafka\\.Log4jController` matches MBeans within `kafka` domain that have `type=kafka.Log4jController` key property. Additional key properties are simply ignored and don't affect the match result.\n* `kafka.*::MeanRate|.*MinuteRate` matches if the attribute name matches `MeanRate|.*MinuteRate` and the domain name matches `kafka.*`.\n* `java.lang:type=Threading:AllThreadIds`\n\nNotes\n* `:`, `,`, and `=` inside regex need to be escaped with `\\`. They are special characters that constructs the pattern.\n* Pattern matches are done against *unquoted* key properties. For example, `domain:name=foo` matches an ObjectName `domain:name=\\\"foo\\\"`.\n\n##### Using Captures\n\nJust like normal regex, named capturing groups can be used to extract substrings from ObjectName and attribute names.\n\nExample:\n\nhttps://github.com/eiiches/scriptable-jmx-exporter/blob/6d3dfeccd3d1d95e7643d342ec8f772150721600/examples/apache-hbase/scriptable-jmx-exporter.yaml#L18-L20\n\nThe captured groups are made available as `match` object (`Map\u003cString, String\u003e`) inside transform scripts.\n\n#### Condition Expression\n\nCondition expression, if set, further narrows down MBean attributes that the rule applies to, in addition to `pattern`.\nIf the condition evaluates to `false`, the MBean attribute will be handled by one of the subsequent rules (or the default rule if there's none).\n\nThe following variables are accessible from a condition expression.\n\n| Variable Name | Type | Description |\n|-|-|-|\n| `mbeanInfo` | [javax.management.MBeanInfo](https://docs.oracle.com/en/java/javase/14/docs/api/java.management/javax/management/MBeanInfo.html) | MBean information |\n| `attributeInfo` | [javax.management.MBeanAttributeInfo](https://docs.oracle.com/en/java/javase/14/docs/api/java.management/javax/management/MBeanAttributeInfo.html) | MBean attribute information |\n\n##### Examples\n\n* `mbeanInfo.getClassName().endsWith(\"JmxReporter$Timer\")`\n\nScripting\n---------\n\nIn this section, we mainly talk about transform scripts for use in `rules[].transform`.\n\nScripts can explicitly specify which scripting engine to use, by starting a script with `!\u003cNAME\u003e` directive. Currently, `!java` is the default (and only) engine and hence can be omitted.\nThere used to be `!jq` engine, but removed.\n\n### Java\n\nJava scripting is powered by [Janino](https://janino-compiler.github.io/janino/), which is a super-small, super-fast Java compiler.\n\n```yaml\n- transform: |\n    !java\n    V1.transform(in, out, \"type\");\n```\n\nTwo variables, `in` (type: [AttributeValue](src/main/java/net/thisptr/jmx/exporter/agent/scripting/janino/api/AttributeValue.java)) and `out` (type: [MetricValueOutput](src/main/java/net/thisptr/jmx/exporter/agent/scripting/janino/api/MetricValueOutput.java)) is provided.\n\nWhat the script has to do is to, transform `in`, which is a value (and metadata) of MBean attribute, into a [MetricValue](src/main/java/net/thisptr/jmx/exporter/agent/scripting/janino/api/MetricValue.java) object and call `out.emit(...)` with the metric object.\n\n#### Helper Functions (V1)\n\nImplementing the transformation from scratch is not easy. So, we provide [V1](src/main/java/net/thisptr/jmx/exporter/agent/scripting/janino/api/v1/V1.java), a set of generic helper functions.\nIn most cases, doing one of the following is sufficient to achieve the desired output.\n * Change arguments to `V1.transform(...)`\n * Modify `in` before calling `V1.transform(...)`\n * Wrap `out` by anonymous inner class to modify `V1.transform(...)` output\n\n##### Case-style Conversion\n\n*NOTE: We DO NOT recommend any case-style conversions.\nWhile [Cc]amelCase with `_` in-between looks somewhat unpleasant, it conveys more information from the original ObjectName,\nprobably making it easier to track a Prometheus metric back to the corresponding MBean attribute later when debugging, etc.*\n\nYou can covert case-styles of metric name by using `V1.snakeCase()` or `V1.lowerCase()`.\n\n###### Example: `java.lang:type=ClassLoading:LoadedClassCount`\n\n| Transform Script | Prometheus Metric Example |\n|-|-|\n| `V1.transform(in, out, \"type\")` | `java_lang_ClassLoading_LoadedClassCount` |\n| `V1.transform(in, out, \"type\", V1.snakeCase())` | `java_lang_class_loading_loaded_class_count` |\n| `V1.transform(in, out, \"type\", V1.lowerCase())` | `java_lang_classloading_loadedclasscount` |\n\n#### Examples\n\n##### Example: Exposing all attributes of all MBaens\n\nFor most of the applications, this rule covers most of the MBean attributes.\n\n```yaml\n- transform: |\n    !java\n    V1.transform(in, out, \"type\");\n```\n\n```\njava_nio_BufferPool_Count{name=\"direct\",} 8 1596881052752\njava_lang_GarbageCollector_LastGcInfo_memoryUsageAfterGc_value_committed{name=\"G1 Young Generation\",key=\"CodeHeap 'profiled nmethods'\",} 2752512 1596881052753\njava_lang_Memory_HeapMemoryUsage_committed 1061158912 1596881052757\n...\n```\n\n##### Example: Exposing versions as info-style metrics (Advanced)\n\n```yaml\n- pattern:\n  - java.lang:type=Runtime:VmVersion\n  - java.lang:type=OperatingSystem:Version\n  transform: |\n    !java\n    import java.util.HashMap;\n    MetricValue m = new MetricValue();\n    m.name = in.domain + \"_\" + in.keyProperties.get(\"type\") + \"_\" + in.attributeName + \"_info\";\n    m.labels = new HashMap\u003c\u003e();\n    m.labels.put(\"version\", (String) in.value);\n    m.value = 1.0;\n    m.timestamp = in.timestamp;\n    out.emit(m);\n```\n\n```\njava_lang_Runtime_VmVersion_info{version=\"14.0.1+7\",} 1.0 1595167009825\njava_lang_OperatingSystem_Version_info{version=\"5.7.4-arch1-1\",} 1.0 1595167009828\n```\n\nReference: [Exposing the software version to Prometheus](https://www.robustperception.io/exposing-the-software-version-to-prometheus)\n\n##### Example: Exposing thread counts by thread state (Advanced)\n\n```yaml\n- pattern: java.lang:type=Threading:AllThreadIds\n  transform: |\n    !java\n    import java.lang.management.ManagementFactory;\n    import java.lang.management.ThreadInfo;\n    import java.lang.management.ThreadMXBean;\n    import java.util.HashMap;\n\n    Thread.State[] states = Thread.State.values();\n    int[] counts = new int[states.length];\n\n    long timestamp = System.currentTimeMillis();\n    ThreadInfo[] threads = ManagementFactory.getThreadMXBean().getThreadInfo((long[]) in.value, 0);\n    for (ThreadInfo thread : threads) {\n      if (thread == null)\n        continue;\n      ++counts[thread.getThreadState().ordinal()];\n    }\n\n    for (int i = 0; i \u003c states.length; ++i) {\n      MetricValue m = new MetricValue();\n      m.name = \"java_lang_threading_state_count\";\n      m.labels = new HashMap\u003c\u003e();\n      m.labels.put(\"state\", states[i].name());\n      m.value = counts[i];\n      m.timestamp = timestamp;\n      m.type = \"gauge\";\n      m.help = \"The number of threads in the state. This value is calculated from ThreadMXBean#getThreadInfo(java.lang:type=Threading:AllThreadIds).\";\n      out.emit(m);\n    }\n```\n\n```\n# HELP java_lang_threading_state_count The number of threads in the state. This value is calculated from ThreadMXBean#getThreadInfo(java.lang:type=Threading:AllThreadIds).\n# TYPE java_lang_threading_state_count gauge\njava_lang_threading_state_count{state=\"NEW\",} 0.0 1595170784228\njava_lang_threading_state_count{state=\"RUNNABLE\",} 11.0 1595170784228\njava_lang_threading_state_count{state=\"BLOCKED\",} 0.0 1595170784228\njava_lang_threading_state_count{state=\"WAITING\",} 1.0 1595170784228\njava_lang_threading_state_count{state=\"TIMED_WAITING\",} 3.0 1595170784228\njava_lang_threading_state_count{state=\"TERMINATED\",} 0.0 1595170784228\n```\n\n##### Example: Adding computed metrics (Advanced)\n\nThis is just for demonstration purpose and highly discouraged in practice unless absolutely necessary because these kind of metrics computation makes it hard to trace a metric back to its source and how the value is generated. In most cases, we don't have to do this at all, because Prometheus can perform complex query including arithmetic.\n\n```yaml\n- pattern: 'java\\\\.lang:type=OperatingSystem:OpenFileDescriptorCount'\n  transform: |\n    !java\n    import java.lang.management.ManagementFactory; // imports must come first\n    import javax.management.ObjectName;\n\n    V1.transform(in, out, \"type\", V1.gauge()); // emit raw metric\n\n    // modify name and values and emit computed metric\n    long max = (Long) ManagementFactory.getPlatformMBeanServer().getAttribute(new ObjectName(\"java.lang:type=OperatingSystem\"), \"MaxFileDescriptorCount\");\n    in.value = max - (Long) in.value;\n    in.attributeName = \"AvailableFileDescriptorCount\";\n    in.attributeDescription = \"The number of file descriptors available to be opened in this JVM, which is calculated as java.lang:type=OperatingSystem:MaxFileDescriptorCount - java.lang:type=OperatingSystem:OpenFileDescriptorCount.\";\n    V1.transform(in, out, \"type\", V1.gauge());\n```\n\n```\n# HELP java_lang_OperatingSystem_OpenFileDescriptorCount OpenFileDescriptorCount\n# TYPE java_lang_OperatingSystem_OpenFileDescriptorCount gauge\njava_lang_OperatingSystem_OpenFileDescriptorCount 29 1596880934872\n# HELP java_lang_OperatingSystem_AvailableFileDescriptorCount The number of file descriptors available to be opened in this JVM, which is calculated as java.lang:type=OperatingSystem:MaxFileDescriptorCount - java.lang:type=OperatingSystem:OpenFileDescriptorCount.\n# TYPE java_lang_OperatingSystem_AvailableFileDescriptorCount gauge\njava_lang_OperatingSystem_AvailableFileDescriptorCount 1048547 1596880934872\n```\n\n#### Getting ready for upcoming OpenMetrics support\n\nWhile this exporter does not support OpenMetrics yet, you can prepare for the upcoming OpenMetrics support.\nThe most notable difference between the Prometheus format and the OpenMetrics format is that OpenMetrics requires (not only recommends) `_total` suffix for counter metrics.\nTo ensure conformance to both formats in future, set `total` suffix to `counter` metrics. E.g.\n\n```java\nMetricValue m = new MetricValue();\nm.name = \"\u003cNAME\u003e\"\nm.suffix = \"total\";\nm.type = \"counter\";\nm.value = 1.0;\nout.emit(m);\n```\n\nThis will produce the following responses in respective formats:\n\n* Prometheus (Special-cased to append `_total` to metric name in annotations, when `counter` has `total` suffix)\n\n  ```\n  # TYPE \u003cNAME\u003e_total counter\n  \u003cNAME\u003e_total 1.0\n  ```\n\n* OpenMetrics\n\n  ```\n  # TYPE \u003cNAME\u003e counter\n  \u003cNAME\u003e_total 1.0\n  ```\n\nAll that said, if you prefer to leave the metrics `untyped` to keep configurations simple, that should be also fine.\n\n#### Tips\n\n* Prefer using rule pattern/condition, instead of `if` inside scripts. It's usually faster.\n* Use `static` inside method-local inner class to do things that need to be done once, such as to compile a regex. Note that this should *not* be used to share mutable states because transform scripts are executed concurrently.\n  ```yaml\n    transform: |\n      class Holder {\n        public static final Pattern PATTERN = Pattern.compile(\".*\");\n      }\n      log(Holder.PATTERN.matcher(\"foo\").matches());\n  ```\n\n### Debugging\n\nSometimes it's hard to debug complex `transform` scripts. Here are some tips and tricks to debug them.\n\n#### Changing a log level to FINEST\n\nThis exporter uses JUL framework for logging. Errors caused by user configurations are logged at \u0026gt;= INFO level. Other errors are\nlogged at \u0026lt; INFO level. If you are encountering issues, consider setting log levels to FINEST to see detailed logs.\n\nTo change a log level, create `logging.properties` and set `java.util.logging.config.file` system property to point to the file.\n\n```console\n$ cat logging.properties\nhandlers = java.util.logging.ConsoleHandler\n.level = INFO\njava.util.logging.ConsoleHandler.level = FINEST\njava.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter\njava.util.logging.SimpleFormatter.format = %1$tFT%1$tT.%1$tL %4$-5.5s %3$-80.80s : %5$s%6$s%n\nnet.thisptr.jmx.exporter.agent.level = FINEST\nnet.thisptr.jmx.exporter.agent.shade.level = INFO\n\n$ java -Djava.util.logging.config.file=logging.properties ...\n```\n\nIf you are using jul-to-slf4j or log4j-jul to redirect JUL logs to another backend (such as log4j2, logback, ...), this may not work. Please consult the relevant documentations for your logging framework.\n\n#### Using log() function\n\nIf you are writing transform scripts in Java, you can use `log(fmt, ...)` or `log(obj)` method. The logs will be recorded at INFO level.\n\n```sh\n- pattern: 'java.lang'\n  transform: |\n    !java\n    log(in);\n    log(\"hi\");\n    log(\"test: %s\", in.value); # printf style; see javadoc for String.format()\n    V1.transform(in, out, \"type\");\n```\n\nAlternatively, you can also use `System.out.printf(...)` or `System.err.printf(...)` as in any other programs.\n\n\nBenchmark\n---------\n\nFirst, it's almost impossible to do a fair comparison. The responses are not the same. Even the number of metrics is not the same.\nPlease also keep in mind that performance is highly dependent on the configurations and these numbers are very specific to the configurations we used for this benchmark.\n\nSee [examples/benchmark-kafka](examples/benchmark-kafka) for the setup details. Here are the results:\n\n| Exporter | Config File (# of lines) | # of Metrics (\\*1) | Throughput [req/s] | Avg. Latency [ms] \u003cbr/\u003e @ 10 [req/s] |\n|-|-|-|-|-|\n| scriptable-jmx-exporter | [scriptable-jmx-exporter.yaml](examples/benchmark-kafka/scriptable-jmx-exporter.yaml) (54) | 3362 | 939.45 | TBD |\n| jmx_exporter 0.13.0 | [kafka-2_0_0.yml](https://github.com/prometheus/jmx_exporter/blob/ce04b7dca8615d724d8f447fa25c44ae1c29238b/example_configs/kafka-2_0_0.yml) (103) | 3157 | 12.14 | TBD |\n\n(\\*) Benchmarked on Intel Core i5-9600K (with Turbo Boost disabled), Linux 5.7.4. (\\*1) kafka-2_0_0.yml seems to be missing a number of metrics, such as `kafka.server:type=socket-server-metrics`.\nWe excluded such metrics as well. The difference in the number of metrics mostly comes from how we treat JVM metrics.\n\nNOTE: This benchmark result is quite old. I am aware of many performance improvement efforts in recent jmx_exporter and this benchmark has to be updated when I have time.\n\nReferences\n----------\n\n- [Java Management Extensions (JMX) - Best Practices](http://www.oracle.com/technetwork/articles/java/best-practices-jsp-136021.html)\n\n\nLicense\n-------\n\nThe MIT License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feiiches%2Fscriptable-jmx-exporter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feiiches%2Fscriptable-jmx-exporter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feiiches%2Fscriptable-jmx-exporter/lists"}