diff --git a/.github/workflows/deploy-snapshot.yaml b/.github/workflows/deploy-snapshot.yaml index d950876..a0d38d4 100644 --- a/.github/workflows/deploy-snapshot.yaml +++ b/.github/workflows/deploy-snapshot.yaml @@ -9,10 +9,13 @@ jobs: runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v1 - - name: Set up JDK 1.8 - uses: actions/setup-java@v1 + - name: Set up JDK 17 + uses: actions/setup-java@v2.3.0 with: - java-version: 1.8 + java-version: '17' + distribution: 'zulu' + - name: install deps + run: deps/install.sh - name: Configure Maven env: M2_SETTINGS_XML: ${{ secrets.M2_SETTINGS_XML }} diff --git a/.gitignore b/.gitignore index 5d37edb..e67dc1e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ -/dependency-reduced-pom.xml -/target/ -/.classpath -/.settings -/.project -/pom.xml.releaseBackup -/release.properties +dependency-reduced-pom.xml +target/ +.classpath +.settings +.project +pom.xml.releaseBackup +release.properties diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..dc2729d --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "deps/janino"] + path = deps/janino + url = https://github.com/janino-compiler/janino diff --git a/README.md b/README.md index 921d9db..d5ae78b 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Scriptable JMX Exporter ======================= -Java agent to scrape and expose MBeans to Prometheus. Formerly, java-prometheus-metrics-agent. +Java agent to scrape and expose MBeans to Prometheus. [![GitHub Actions](https://github.com/eiiches/scriptable-jmx-exporter/workflows/test/badge.svg)](https://github.com/eiiches/scriptable-jmx-exporter/actions) @@ -22,6 +22,8 @@ Features - Decomposing complex MBean name into metric labels. - Performance. Goal is to enable a large number of metrics (~50k) at shorter intervals (>1s) without impacting workloads. - See our [benchmark](#benchmark). +- Java Flight Recorder (JFR) Event Streaming (>=Java 14) + - You can aggregate JFR events into custom metrics. #### Why another exporter? There's a bunch of exporters and there's even the official one. @@ -32,8 +34,8 @@ I needed something that can scrape many MBeans with a small number of rules. Wri #### Requirements -* Java 8 or newer - +* Java 8 (Minimum) + * JFR Event Streaming support requires Java 14 or newer Quick Start ------------ @@ -126,6 +128,8 @@ declarations: | public static void foo() { log("foo"); } + public static Counter jvmAllocationRate = Counter.builder("jvm_allocation_rate") + .register(Registry.getInstance()); rules: - pattern: # Drop less useful attributes JVM exposes. @@ -144,6 +148,14 @@ rules: # Default rule to cover the rest. - transform: | V1.transform(in, out, "type"); +flight_recorder_events: +- name: jdk.ObjectAllocationInNewTLAB + handler: | + jvmAllocationRate.increment(event.getLong("tlabSize")); +- name: jdk.ObjectAllocationOutsideTLAB + handler: | + jvmAllocationRate.increment(event.getLong("allocationSize")); + ``` This 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. @@ -169,8 +181,8 @@ These options can be overridden by URL parameters. E.g. `/metrics?minimum_respon ### Declarations -You 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. -Make sure to add `public static` in the declarations; otherwise, the classes and methods won't be accessible. +The classes, methods and variables defined here will be automatically imported and can be referenced from other places (e.g. MBean transform scripts, condition expression, and JFR event handlers). +You can also define and register custom metrics here. ```yaml declarations: | @@ -183,9 +195,14 @@ declarations: | public static class Foo { // ... } + + public static Counter jvmAllocationRate = Counter.builder("jvm_allocation_rate") + .register(Registry.getInstance()); ``` -### Rule Configuration +> NOTE: Make sure to use `public static` modifiers. + +### MBean Rule Configuration Rules are searched in order and a first match is used for each attribute. @@ -219,6 +236,33 @@ The following variables are accessible from a condition expression. * `mbeanInfo.getClassName().endsWith("JmxReporter$Timer")` +### Flight Recorder Events + +You can subscribe events from Java Flight Recorder (JFR) event stream. + +```yaml +flight_recorder_events: +- name: .* + handler: | + Counter.builder("java_flight_recorder_events") + .tags("type", event.getEventType().getName()) + .register(Registry.getInstance()) + .increment(); +``` + +| Config Key | Default | Description | +|-|-|-| +| `flight_recorder_events[].name` | - | The type of the event to subscribe. E.g. `jdk.ObjectAllocationInNewTLAB` | +| `flight_recorder_events[].handler` | - | The script to execute when the event is generated. | + +The following variables are accessible from the handler script. + +| Variable Name | Type | Description | +|-|-|-| +| `event` | [jdk.jfr.consumer.RecordedEvent](https://docs.oracle.com/en/java/javase/14/docs/api/jdk.jfr/jdk/jfr/consumer/RecordedEvent.html) | The generated event | + +You can use custom JFR events too. Refer to [Creating and Recording Your First Event](https://docs.oracle.com/en/java/javase/14/jfapi/creating-and-recording-your-first-event.html) to learn how to create custom events. + Scripting --------- diff --git a/deps/install.sh b/deps/install.sh new file mode 100755 index 0000000..aa42b83 --- /dev/null +++ b/deps/install.sh @@ -0,0 +1,24 @@ +#!/bin/bash +set -euo pipefail + +scriptpath="$(readlink -f "$0")" +scriptdir="$(dirname "$scriptpath")" +cd "$scriptdir" + +git submodule update --force --recursive --init janino +git -C janino clean -fdx +base_version="$(git -C janino rev-parse HEAD | cut -c 1-7)" +patch_version="$(cat janino.patch.d/*.patch | sha1sum | cut -c 1-5)" +version="0.0.0-$base_version.$patch_version" + +for patch in janino.patch.d/*.patch; do + patch="$(readlink -f "$patch")" + git -C janino am "$patch" +done + +(cd janino/janino-parent \ + && mvn versions:set -DnewVersion="$version" \ + && mvn clean install) + +git submodule update --force --recursive --init janino +git -C janino clean -fdx diff --git a/deps/janino b/deps/janino new file mode 160000 index 0000000..a796a97 --- /dev/null +++ b/deps/janino @@ -0,0 +1 @@ +Subproject commit a796a975c66a7b37a5dcd6f54d428cd6774bc796 diff --git a/deps/janino.patch.d/0001-compile-with-target-1.7-source-1.7.patch b/deps/janino.patch.d/0001-compile-with-target-1.7-source-1.7.patch new file mode 100644 index 0000000..7e01415 --- /dev/null +++ b/deps/janino.patch.d/0001-compile-with-target-1.7-source-1.7.patch @@ -0,0 +1,27 @@ +From 5e8bee8cc526ab149881a036cb950e6d6c3d2de5 Mon Sep 17 00:00:00 2001 +From: Eiichi Sato +Date: Mon, 18 Oct 2021 02:58:26 +0900 +Subject: [PATCH] compile with -target 1.7 -source 1.7 + +--- + janino-parent/pom.xml | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/janino-parent/pom.xml b/janino-parent/pom.xml +index 04b4d50b..5c387b7c 100644 +--- a/janino-parent/pom.xml ++++ b/janino-parent/pom.xml +@@ -13,8 +13,8 @@ + +- 1.6 +- 1.6 ++ 1.7 ++ 1.7 + +