diff --git a/.editorconfig b/.editorconfig index b33efbd87..1ade83fa3 100644 --- a/.editorconfig +++ b/.editorconfig @@ -4,5 +4,15 @@ root = true max_line_length = 100 indent_size = 2 +[{version-rules.xml,maven-wrapper.properties,checkstyle.xml,docker-compose.yaml,docker-compose.yml,Dockerfile,example_target_info.json,mise.toml,mise.lock,mvnm,mvnw.cmd,generate-protobuf.sh,super-linter.env,.gitleaksignore}] +max_line_length = 200 + +[{grafana-dashboard-*.json,.editorconfig}] +max_line_length = 300 + [pom.xml] +max_line_length = 110 + +[*.py] +# checked by black indent_size = 4 diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 505013ce1..c6485ad12 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,3 +1,4 @@ +--- version: 2 updates: - package-ecosystem: "github-actions" @@ -5,8 +6,10 @@ updates: schedule: interval: weekly - package-ecosystem: maven - # excluding simpleclient_archive from the update is not possible, only includes are supported - # when we use includes, we run into https://github.com/dependabot/dependabot-core/issues/10415 - + # excluding simpleclient_archive from the update is not possible, + # only includes are supported + # when we use includes, + # we run into https://github.com/dependabot/dependabot-core/issues/10415 # even if we limit to 1 PR at a time # therefore we just rename pom.xml in simpleclient_archive for now # if this becomes a problem, we can move to renovate diff --git a/.github/super-linter.env b/.github/super-linter.env new file mode 100644 index 000000000..8d10a7d3b --- /dev/null +++ b/.github/super-linter.env @@ -0,0 +1,34 @@ +FILTER_REGEX_EXCLUDE=mvnw|src/main/generated/.*|docs/themes/.*|keystore.pkcs12|.*.java|prometheus-metrics-exporter-opentelemetry-shaded/pom.xml +IGNORE_GITIGNORED_FILES=true +JAVA_FILE_NAME=google_checks.xml +# disable kubernetes linter - complains about resource limits, etc +VALIDATE_CHECKOV=false +VALIDATE_CSS=false +VALIDATE_CSS_PRETTIER=false +VALIDATE_DOCKERFILE_HADOLINT=false +VALIDATE_GIT_COMMITLINT=false +# done by maven +VALIDATE_GOOGLE_JAVA_FORMAT=false +# times out +VALIDATE_GO_MODULES=false +VALIDATE_HTML=false +# done by checkstyle +VALIDATE_JAVA=false +# contradicting with prettier +VALIDATE_JAVASCRIPT_STANDARD=false +# we have many duplicate code in our codebase for demo purposes +VALIDATE_JSCPD=false +VALIDATE_PYTHON_PYLINT=false + +FIX_ENV=true +FIX_GO=true +FIX_JAVASCRIPT_PRETTIER=true +FIX_JSON=true +FIX_JSONC=true +FIX_JSONC_PRETTIER=true +FIX_JSON_PRETTIER=true +FIX_MARKDOWN=true +FIX_MARKDOWN_PRETTIER=true +FIX_PYTHON_BLACK=true +FIX_SHELL_SHFMT=true +FIX_YAML_PRETTIER=true diff --git a/.github/workflows/acceptance-tests.yml b/.github/workflows/acceptance-tests.yml index 334602715..c114d177a 100644 --- a/.github/workflows/acceptance-tests.yml +++ b/.github/workflows/acceptance-tests.yml @@ -1,10 +1,11 @@ +--- name: OpenTelemetry Acceptance Tests on: push: - branches: [ "main" ] + branches: ["main"] pull_request: - branches: [ "main" ] + branches: ["main"] permissions: {} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 679ce1752..09cfd7e15 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,10 +1,11 @@ +--- name: Build on: push: - branches: [ "main" ] + branches: ["main"] pull_request: - branches: [ "main" ] + branches: ["main"] permissions: {} @@ -25,4 +26,3 @@ jobs: ${{ runner.os }}-maven- - name: Run the Maven verify phase run: mise run ci - diff --git a/.github/workflows/github-pages.yaml b/.github/workflows/github-pages.yaml index 0f1b8ac5c..5cba7fea6 100644 --- a/.github/workflows/github-pages.yaml +++ b/.github/workflows/github-pages.yaml @@ -13,8 +13,10 @@ on: permissions: {} -# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. -# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. +# Allow only one concurrent deployment, skipping runs queued between +# the run in-progress and latest queued. +# However, do NOT cancel in-progress runs as we want to allow +# these production deployments to complete. concurrency: group: "pages" cancel-in-progress: false @@ -32,22 +34,18 @@ jobs: - uses: actions/checkout@v4 with: persist-credentials: false - fetch-tags: 'true' + fetch-tags: "true" fetch-depth: 0 - uses: jdx/mise-action@7a111ead46986ccad89a74ad013ba2a7c08c9e67 # v2.1.1 with: - cache: 'false' + cache: "false" - name: Prepare GitHub Pages run: mise run prepare-gh-pages - with: - permissions: block - name: Setup Pages id: pages uses: actions/configure-pages@v5 - name: Build GitHub Pages run: mise run build-gh-pages - with: - permissions: block - name: Upload artifact uses: actions/upload-pages-artifact@v3 with: diff --git a/.github/workflows/lint.yml b/.github/workflows/lint-rest.yml similarity index 88% rename from .github/workflows/lint.yml rename to .github/workflows/lint-rest.yml index ee3cffab2..8a747cf94 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint-rest.yml @@ -7,7 +7,6 @@ permissions: {} jobs: acceptance-tests: - permissions: {} runs-on: ubuntu-24.04 steps: - name: Check out @@ -16,5 +15,4 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: jdx/mise-action@7a111ead46986ccad89a74ad013ba2a7c08c9e67 # v2.1.1 - name: Lint - run: mise run lint-all - + run: mise run lint-rest diff --git a/.github/workflows/native-tests.yml b/.github/workflows/native-tests.yml index 6d21a5faa..d5b3927db 100644 --- a/.github/workflows/native-tests.yml +++ b/.github/workflows/native-tests.yml @@ -1,10 +1,11 @@ +--- name: GraalVM Native Tests on: push: - branches: [ "main" ] + branches: ["main"] pull_request: - branches: [ "main" ] + branches: ["main"] permissions: {} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bf0e60d02..087356453 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,3 +1,4 @@ +--- name: Deploy to Maven Central on: @@ -14,10 +15,10 @@ jobs: steps: - name: Debug gpg key - remove after debugging env: - GPG_SIGNING_KEY: ${{ secrets.GPG_SIGNING_KEY }} + GPG_SIGNING_KEY: ${{ secrets.GPG_SIGNING_KEY }} run: | - echo "$GPG_SIGNING_KEY" | wc -c - echo "$GPG_SIGNING_KEY" | gpg --batch --import-options import-show --import + echo "${#GPG_SIGNING_KEY}" + echo "${GPG_SIGNING_KEY}" | gpg --batch --import-options import-show --import - name: Checkout Plugin Repository uses: actions/checkout@v4 with: @@ -37,8 +38,8 @@ jobs: - name: Set up Apache Maven Central uses: actions/setup-java@v4 with: - distribution: 'temurin' - java-version: '17' + distribution: "temurin" + java-version: "17" server-id: ossrh server-username: MAVEN_USERNAME server-password: MAVEN_CENTRAL_TOKEN diff --git a/.github/workflows/super-linter.yml b/.github/workflows/super-linter.yml new file mode 100644 index 000000000..102695d4b --- /dev/null +++ b/.github/workflows/super-linter.yml @@ -0,0 +1,31 @@ +--- +name: Lint + +on: + pull_request: + +jobs: + lint: + runs-on: ubuntu-24.04 + + permissions: + contents: read + packages: read + # To report GitHub Actions status checks + statuses: write + + steps: + - name: Checkout code + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + fetch-depth: 0 + + - name: Load super-linter configuration + run: grep -v '^#' .github/super-linter.env | grep -v 'FIX_' >> "$GITHUB_ENV" + + - name: Super-linter + uses: super-linter/super-linter@4e8a7c2bf106c4c766c816b35ec612638dc9b6b2 # v7.3.0 + env: + # To report GitHub Actions status checks + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index ad343c1bd..b727017a9 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,5 @@ dependency-reduced-pom.xml **/.classpath **.project **/.settings/ +docs/public +.lycheecache diff --git a/.gitleaksignore b/.gitleaksignore new file mode 100644 index 000000000..605fefa97 --- /dev/null +++ b/.gitleaksignore @@ -0,0 +1,2 @@ +/tmp/lint/integration-tests/it-pushgateway/src/test/resources/pushgateway-ssl.yaml:private-key:36 +/github/workspace/integration-tests/it-pushgateway/src/test/resources/pushgateway-ssl.yaml:private-key:36 diff --git a/.yaml-lint.yml b/.yaml-lint.yml new file mode 100644 index 000000000..a06ffeed5 --- /dev/null +++ b/.yaml-lint.yml @@ -0,0 +1,5 @@ +extends: relaxed + +rules: + line-length: + max: 120 diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index d325872bd..524d1ab50 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,3 +1,4 @@ # Prometheus Community Code of Conduct -Prometheus follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/main/code-of-conduct.md). +Prometheus follows the +[CNCF Code of Conduct](https://github.com/cncf/foundation/blob/main/code-of-conduct.md). diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ff9717f67..aaa08ea7d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,18 +2,19 @@ Prometheus uses GitHub to manage reviews of pull requests. -* If you have a trivial fix or improvement, go ahead and create a pull request, +- If you have a trivial fix or improvement, go ahead and create a pull request, addressing (with `@...`) the maintainer of this repository (see [MAINTAINERS.md](MAINTAINERS.md)) in the description of the pull request. -* If you plan to do something more involved, first discuss your ideas +- If you plan to do something more involved, first discuss your ideas on our [mailing list](https://groups.google.com/forum/?fromgroups#!forum/prometheus-developers). This will avoid unnecessary work and surely give you and us a good deal of inspiration. ## Formatting -This repository uses [Google Java Format](https://github.com/google/google-java-format) to format the code. +This repository uses [Google Java Format](https://github.com/google/google-java-format) to format +the code. Run `./mvnw spotless:apply` to format the code (only changed files) before committing. @@ -21,7 +22,8 @@ Run `./mvnw spotless:apply` to format the code (only changed files) before commi If you're getting errors when running tests: -- Make sure that the IDE uses only the "Maven Shade" dependency of "prometheus-metrics-exposition-formats" and the "prometheus-metrics-tracer*" dependencies. +- Make sure that the IDE uses only the "Maven Shade" dependency of " + prometheus-metrics-exposition-formats" and the "prometheus-metrics-tracer\*" dependencies. ### Avoid failures while running tests @@ -30,7 +32,8 @@ If you're getting errors when running tests: - Use `-Dcheckstyle.skip=true` to skip the checkstyle check during development. - Use `-Dwarnings=-nowarn` to skip the warnings during development. -Combine all with `./mvnw test -DskipTests=true -Dspotless.check.skip=true -Dcoverage.skip=true -Dcheckstyle.skip=true -Dwarnings=-nowarn`. +Combine all with +`./mvnw test -DskipTests=true -Dspotless.check.skip=true -Dcoverage.skip=true -Dcheckstyle.skip=true -Dwarnings=-nowarn`. # editorconfig-checker-disable-line ## Updating the Protobuf Java Classes diff --git a/MAINTAINERS.md b/MAINTAINERS.md index dae5c71de..cf0a885eb 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -1,4 +1,6 @@ -* Fabian Stäber @fstab -* Doug Hoard @dhoard -* Tom Wilkie @tomwilkie -* Gregor Zeitlinger @zeitlinger +# Maintainers + +- Fabian Stäber @fstab +- Doug Hoard @dhoard +- Tom Wilkie @tomwilkie +- Gregor Zeitlinger @zeitlinger diff --git a/README.md b/README.md index f03a3e2a6..6e62e3577 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,25 @@ # Prometheus Java Metrics Library -[![Build](https://github.com/prometheus/client_java/actions/workflows/build.yml/badge.svg)](https://github.com/prometheus/client_java/actions/workflows/build.yml) java 8+ Apache 2.0 +[![Build](https://github.com/prometheus/client_java/actions/workflows/build.yml/badge.svg)](https://github.com/prometheus/client_java/actions/workflows/build.yml) java 8+ Apache 2.0 # editorconfig-checker-disable-line -# Documentation +## Documentation [https://prometheus.github.io/client_java](https://prometheus.github.io/client_java) -# Contributing and community +## Contributing and community -See [CONTRIBUTING.md](CONTRIBUTING.md) and the [community section](http://prometheus.io/community/) of the Prometheus homepage. +See [CONTRIBUTING.md](CONTRIBUTING.md) and the [community section](http://prometheus.io/community/) +of the Prometheus homepage. -The Prometheus Java community is present on the [CNCF Slack](https://cloud-native.slack.com) on `#prometheus-java`, and we have a fortnightly community call in the [Prometheus public calendar](https://prometheus.io/community/). +The Prometheus Java community is present on the [CNCF Slack](https://cloud-native.slack.com) on +`#prometheus-java`, and we have a fortnightly community call in +the [Prometheus public calendar](https://prometheus.io/community/). -# Previous Releases +## Previous Releases -The source code for 0.16.0 and older is on the [simpleclient](https://github.com/prometheus/client_java/tree/simpleclient) branch. +The source code for 0.16.0 and older is on +the [simpleclient](https://github.com/prometheus/client_java/tree/simpleclient) branch. -# License +## License Apache License 2.0, see [LICENSE](LICENSE). diff --git a/RELEASING.md b/RELEASING.md index eadbb8a76..151fae720 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -1,6 +1,7 @@ -## Create a Release +# Create a Release -1. Go to https://github.com/prometheus/client_java/releases/new +1. Go to 2. Click on "Choose a tag", enter the tag name (e.g. `v0.1.0`), and click "Create a new tag". -3. Click on "Generate release notes" to auto-generate the release notes based on the commits since the last release. +3. Click on "Generate release notes" to auto-generate the release notes based on the commits since + the last release. 4. Click on "Publish release". diff --git a/benchmarks/README.md b/benchmarks/README.md index 36300e4d1..cb445c7bf 100644 --- a/benchmarks/README.md +++ b/benchmarks/README.md @@ -1,15 +1,14 @@ -Benchmarks ----------- +# Benchmarks ## How to Run -``` +```shell java -jar ./benchmarks/target/benchmarks.jar ``` Run only one specific benchmark: -``` +```shell java -jar ./benchmarks/target/benchmarks.jar CounterBenchmark ``` @@ -17,16 +16,22 @@ java -jar ./benchmarks/target/benchmarks.jar CounterBenchmark See Javadoc of the benchmark classes: -* [CounterBenchmark](https://github.com/prometheus/client_java/blob/1.0.x/benchmarks/src/main/java/io/prometheus/metrics/benchmarks/CounterBenchmark.java) -* [HistogramBenchmark](https://github.com/prometheus/client_java/blob/1.0.x/benchmarks/src/main/java/io/prometheus/metrics/benchmarks/HistogramBenchmark.java) +- [CounterBenchmark](https://github.com/prometheus/client_java/blob/1.0.x/benchmarks/src/main/java/io/prometheus/metrics/benchmarks/CounterBenchmark.java) +- [HistogramBenchmark](https://github.com/prometheus/client_java/blob/1.0.x/benchmarks/src/main/java/io/prometheus/metrics/benchmarks/HistogramBenchmark.java) ## What Prometheus Java client optimizes for concurrent updates of metrics in multi-threaded applications. -If your application is single-threaded and uses only one processor core, your application isn't performance critical anyway. -If your application is designed to use all available processor cores for maximum performance, then you want a metric library that doesn't slow your application down. -Prometheus client Java metrics support concurrent updates and scrapes. This shows in benchmarks with multiple threads recording data in shared metrics. +If your application is single-threaded and uses only one processor core, your application isn't +performance critical anyway. +If your application is designed to use all available processor cores for maximum performance, then +you want a metric library that doesn't slow your +application down. +Prometheus client Java metrics support concurrent updates and scrapes. This shows in benchmarks with +multiple threads recording data in shared +metrics. ## Archive -The `src/main/archive/` directory contains the old benchmarks from 0.16.0 and earlier. It will be removed as soon as all benchmarks are ported to the 1.0.0 release. +The `src/main/archive/` directory contains the old benchmarks from 0.16.0 and earlier. It will be +removed as soon as all benchmarks are ported to the 1.0.0 release. diff --git a/benchmarks/pom.xml b/benchmarks/pom.xml index 8e476d5a6..3cdbc09c0 100644 --- a/benchmarks/pom.xml +++ b/benchmarks/pom.xml @@ -1,122 +1,125 @@ - - 4.0.0 + + 4.0.0 - - io.prometheus - client_java - 1.4.0-SNAPSHOT - + + io.prometheus + client_java + 1.4.0-SNAPSHOT + - benchmarks + benchmarks - Prometheus Java Client Benchmarks - - Benchmarks of client performance, and comparison to other systems. - + Prometheus Java Client Benchmarks + + Benchmarks of client performance, and comparison to other systems. + - - 1.37 - 0.16.0 - 3.0.2 - true - - - - - - io.opentelemetry.instrumentation - opentelemetry-instrumentation-bom-alpha - ${otel.instrumentation.version} - pom - import - - - + + 1.37 + 0.16.0 + 3.0.2 + true + + - - org.openjdk.jmh - jmh-core - ${jmh.version} - - - io.prometheus - prometheus-metrics-core - ${project.version} - - - io.prometheus - prometheus-metrics-exposition-textformats - ${project.version} - - - io.prometheus - simpleclient - ${simpleclient.version} - - - com.codahale.metrics - metrics-core - ${codahale.version} - - - io.opentelemetry - opentelemetry-api - - - io.opentelemetry - opentelemetry-sdk - - - io.opentelemetry - opentelemetry-sdk-testing - + + io.opentelemetry.instrumentation + opentelemetry-instrumentation-bom-alpha + ${otel.instrumentation.version} + pom + import + - - ${project.artifactId} - - - org.apache.maven.plugins - maven-compiler-plugin - - 1.8 - 1.8 - - - -parameters - - - - org.openjdk.jmh - jmh-generator-annprocess - ${jmh.version} - - - - - - org.apache.maven.plugins - maven-shade-plugin - - - package - - shade - - - benchmarks - - - io.prometheus.metrics.benchmarks.BenchmarkRunner - - - - - - - - + + + + + org.openjdk.jmh + jmh-core + ${jmh.version} + + + io.prometheus + prometheus-metrics-core + ${project.version} + + + io.prometheus + prometheus-metrics-exposition-textformats + ${project.version} + + + io.prometheus + simpleclient + ${simpleclient.version} + + + com.codahale.metrics + metrics-core + ${codahale.version} + + + io.opentelemetry + opentelemetry-api + + + io.opentelemetry + opentelemetry-sdk + + + io.opentelemetry + opentelemetry-sdk-testing + + + + ${project.artifactId} + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.8 + 1.8 + + + -parameters + + + + org.openjdk.jmh + jmh-generator-annprocess + ${jmh.version} + + + + + + org.apache.maven.plugins + maven-shade-plugin + + + package + + shade + + + benchmarks + + + io.prometheus.metrics.benchmarks.BenchmarkRunner + + + + + + + + + diff --git a/benchmarks/src/archive/java/io/prometheus/client/CKMSQuantileBenchmark.java b/benchmarks/src/archive/java/io/prometheus/client/CKMSQuantileBenchmark.java index 530810481..ab383d327 100644 --- a/benchmarks/src/archive/java/io/prometheus/client/CKMSQuantileBenchmark.java +++ b/benchmarks/src/archive/java/io/prometheus/client/CKMSQuantileBenchmark.java @@ -1,6 +1,11 @@ package io.prometheus.client; import io.prometheus.client.CKMSQuantiles.Quantile; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Random; +import java.util.concurrent.TimeUnit; import org.openjdk.jmh.annotations.*; import org.openjdk.jmh.infra.Blackhole; import org.openjdk.jmh.runner.Runner; @@ -8,131 +13,120 @@ import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Random; -import java.util.concurrent.TimeUnit; - public class CKMSQuantileBenchmark { - @State(Scope.Benchmark) - public static class EmptyBenchmarkState { - @Param({"10000", "100000", "1000000"}) - public int value; - - List quantiles; - Random rand = new Random(0); - - List shuffle; - - Quantile mean = new Quantile(0.50, 0.050); - Quantile q90 = new Quantile(0.90, 0.010); - Quantile q95 = new Quantile(0.95, 0.005); - Quantile q99 = new Quantile(0.99, 0.001); - - @Setup(Level.Trial) - public void setup() { - quantiles = new ArrayList(); - quantiles.add(mean); - quantiles.add(q90); - quantiles.add(q95); - quantiles.add(q99); - - shuffle = new ArrayList(value); - for (int i = 0; i < value; i++) { - shuffle.add((double) i); - } - Collections.shuffle(shuffle, rand); - } - } - - @Benchmark - @BenchmarkMode({Mode.AverageTime}) - @OutputTimeUnit(TimeUnit.MILLISECONDS) - public void ckmsQuantileInsertBenchmark(EmptyBenchmarkState state) { - CKMSQuantiles q = new CKMSQuantiles(state.quantiles.toArray(new Quantile[]{})); - for (Double l : state.shuffle) { - q.insert(l); - } - } - - /** prefilled benchmark, means that we already have a filled and compressed samples available */ - @State(Scope.Benchmark) - public static class PrefilledBenchmarkState { - @Param({"10000", "100000", "1000000"}) - public int value; - - - CKMSQuantiles ckmsQuantiles; - - List quantiles; - Random rand = new Random(0); - - Quantile mean = new Quantile(0.50, 0.050); - Quantile q90 = new Quantile(0.90, 0.010); - Quantile q95 = new Quantile(0.95, 0.005); - Quantile q99 = new Quantile(0.99, 0.001); - List shuffle; - - int rank = (int) (value * q95.quantile); - - - @Setup(Level.Trial) - public void setup() { - quantiles = new ArrayList(); - quantiles.add(mean); - quantiles.add(q90); - quantiles.add(q95); - quantiles.add(q99); - - shuffle = new ArrayList(value); - for (int i = 0; i < value; i++) { - shuffle.add((double) i); - } - Collections.shuffle(shuffle, rand); - - - ckmsQuantiles = new CKMSQuantiles(quantiles.toArray(new Quantile[]{})); - for (Double l : shuffle) { - ckmsQuantiles.insert(l); - } - // make sure we inserted all 'hanging' samples (count % 128) - ckmsQuantiles.get(0); - // compress everything so we have a similar samples size regardless of n. - ckmsQuantiles.compress(); - System.out.println("Sample size is: " + ckmsQuantiles.samples.size()); - } - - } - - @Benchmark - @BenchmarkMode({Mode.AverageTime}) - @OutputTimeUnit(TimeUnit.NANOSECONDS) - public void ckmsQuantileGetBenchmark(Blackhole blackhole, PrefilledBenchmarkState state) { - blackhole.consume(state.ckmsQuantiles.get(state.q90.quantile)); + @State(Scope.Benchmark) + public static class EmptyBenchmarkState { + @Param({"10000", "100000", "1000000"}) + public int value; + + List quantiles; + Random rand = new Random(0); + + List shuffle; + + Quantile mean = new Quantile(0.50, 0.050); + Quantile q90 = new Quantile(0.90, 0.010); + Quantile q95 = new Quantile(0.95, 0.005); + Quantile q99 = new Quantile(0.99, 0.001); + + @Setup(Level.Trial) + public void setup() { + quantiles = new ArrayList(); + quantiles.add(mean); + quantiles.add(q90); + quantiles.add(q95); + quantiles.add(q99); + + shuffle = new ArrayList(value); + for (int i = 0; i < value; i++) { + shuffle.add((double) i); + } + Collections.shuffle(shuffle, rand); } - - /** - * benchmark for the f method. - */ - @Benchmark - @BenchmarkMode({Mode.AverageTime}) - @OutputTimeUnit(TimeUnit.NANOSECONDS) - public void ckmsQuantileF(Blackhole blackhole, PrefilledBenchmarkState state) { - blackhole.consume(state.ckmsQuantiles.f(state.rank)); + } + + @Benchmark + @BenchmarkMode({Mode.AverageTime}) + @OutputTimeUnit(TimeUnit.MILLISECONDS) + public void ckmsQuantileInsertBenchmark(EmptyBenchmarkState state) { + CKMSQuantiles q = new CKMSQuantiles(state.quantiles.toArray(new Quantile[] {})); + for (Double l : state.shuffle) { + q.insert(l); } - - public static void main(String[] args) throws RunnerException { - - Options opt = new OptionsBuilder() - .include(CKMSQuantileBenchmark.class.getSimpleName()) - .warmupIterations(5) - .measurementIterations(4) - .threads(1) - .forks(1) - .build(); - - new Runner(opt).run(); + } + + /** prefilled benchmark, means that we already have a filled and compressed samples available */ + @State(Scope.Benchmark) + public static class PrefilledBenchmarkState { + @Param({"10000", "100000", "1000000"}) + public int value; + + CKMSQuantiles ckmsQuantiles; + + List quantiles; + Random rand = new Random(0); + + Quantile mean = new Quantile(0.50, 0.050); + Quantile q90 = new Quantile(0.90, 0.010); + Quantile q95 = new Quantile(0.95, 0.005); + Quantile q99 = new Quantile(0.99, 0.001); + List shuffle; + + int rank = (int) (value * q95.quantile); + + @Setup(Level.Trial) + public void setup() { + quantiles = new ArrayList(); + quantiles.add(mean); + quantiles.add(q90); + quantiles.add(q95); + quantiles.add(q99); + + shuffle = new ArrayList(value); + for (int i = 0; i < value; i++) { + shuffle.add((double) i); + } + Collections.shuffle(shuffle, rand); + + ckmsQuantiles = new CKMSQuantiles(quantiles.toArray(new Quantile[] {})); + for (Double l : shuffle) { + ckmsQuantiles.insert(l); + } + // make sure we inserted all 'hanging' samples (count % 128) + ckmsQuantiles.get(0); + // compress everything so we have a similar samples size regardless of n. + ckmsQuantiles.compress(); + System.out.println("Sample size is: " + ckmsQuantiles.samples.size()); } + } + + @Benchmark + @BenchmarkMode({Mode.AverageTime}) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public void ckmsQuantileGetBenchmark(Blackhole blackhole, PrefilledBenchmarkState state) { + blackhole.consume(state.ckmsQuantiles.get(state.q90.quantile)); + } + + /** benchmark for the f method. */ + @Benchmark + @BenchmarkMode({Mode.AverageTime}) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public void ckmsQuantileF(Blackhole blackhole, PrefilledBenchmarkState state) { + blackhole.consume(state.ckmsQuantiles.f(state.rank)); + } + + public static void main(String[] args) throws RunnerException { + + Options opt = + new OptionsBuilder() + .include(CKMSQuantileBenchmark.class.getSimpleName()) + .warmupIterations(5) + .measurementIterations(4) + .threads(1) + .forks(1) + .build(); + + new Runner(opt).run(); + } } diff --git a/benchmarks/src/archive/java/io/prometheus/client/benchmark/CounterBenchmark.java b/benchmarks/src/archive/java/io/prometheus/client/benchmark/CounterBenchmark.java index 592efc6f2..c37076156 100644 --- a/benchmarks/src/archive/java/io/prometheus/client/benchmark/CounterBenchmark.java +++ b/benchmarks/src/archive/java/io/prometheus/client/benchmark/CounterBenchmark.java @@ -1,6 +1,7 @@ package io.prometheus.client.benchmark; import com.codahale.metrics.MetricRegistry; +import java.util.concurrent.TimeUnit; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Mode; @@ -13,8 +14,6 @@ import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; -import java.util.concurrent.TimeUnit; - @State(Scope.Benchmark) public class CounterBenchmark { @@ -28,16 +27,16 @@ public class CounterBenchmark { @Setup public void setup() { - prometheusSimpleCounter = io.prometheus.client.Counter.build() - .name("name") - .help("some description..") - .labelNames("some", "group").create(); + prometheusSimpleCounter = + io.prometheus.client.Counter.build() + .name("name") + .help("some description..") + .labelNames("some", "group") + .create(); prometheusSimpleCounterChild = prometheusSimpleCounter.labels("test", "group"); - prometheusSimpleCounterNoLabels = io.prometheus.client.Counter.build() - .name("name") - .help("some description..") - .create(); + prometheusSimpleCounterNoLabels = + io.prometheus.client.Counter.build().name("name").help("some description..").create(); registry = new MetricRegistry(); codahaleCounter = registry.counter("counter"); @@ -48,21 +47,21 @@ public void setup() { @BenchmarkMode({Mode.AverageTime}) @OutputTimeUnit(TimeUnit.NANOSECONDS) public void prometheusSimpleCounterIncBenchmark() { - prometheusSimpleCounter.labels("test", "group").inc(); + prometheusSimpleCounter.labels("test", "group").inc(); } - + @Benchmark @BenchmarkMode({Mode.AverageTime}) @OutputTimeUnit(TimeUnit.NANOSECONDS) public void prometheusSimpleCounterChildIncBenchmark() { - prometheusSimpleCounterChild.inc(); + prometheusSimpleCounterChild.inc(); } @Benchmark @BenchmarkMode({Mode.AverageTime}) @OutputTimeUnit(TimeUnit.NANOSECONDS) public void prometheusSimpleCounterNoLabelsIncBenchmark() { - prometheusSimpleCounterNoLabels.inc(); + prometheusSimpleCounterNoLabels.inc(); } @Benchmark @@ -81,13 +80,14 @@ public void codahaleMeterMarkBenchmark() { public static void main(String[] args) throws RunnerException { - Options opt = new OptionsBuilder() - .include(CounterBenchmark.class.getSimpleName()) - .warmupIterations(5) - .measurementIterations(4) - .threads(4) - .forks(1) - .build(); + Options opt = + new OptionsBuilder() + .include(CounterBenchmark.class.getSimpleName()) + .warmupIterations(5) + .measurementIterations(4) + .threads(4) + .forks(1) + .build(); new Runner(opt).run(); } diff --git a/benchmarks/src/archive/java/io/prometheus/client/benchmark/ExemplarsBenchmark.java b/benchmarks/src/archive/java/io/prometheus/client/benchmark/ExemplarsBenchmark.java index 7d033afcd..a3fa45ae1 100644 --- a/benchmarks/src/archive/java/io/prometheus/client/benchmark/ExemplarsBenchmark.java +++ b/benchmarks/src/archive/java/io/prometheus/client/benchmark/ExemplarsBenchmark.java @@ -3,6 +3,7 @@ import io.prometheus.client.Counter; import io.prometheus.client.exemplars.DefaultExemplarSampler; import io.prometheus.client.exemplars.tracer.common.SpanContextSupplier; +import java.util.concurrent.TimeUnit; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Mode; @@ -11,8 +12,6 @@ import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; -import java.util.concurrent.TimeUnit; - @State(Scope.Benchmark) public class ExemplarsBenchmark { @@ -23,25 +22,28 @@ public class ExemplarsBenchmark { @Setup public void setup() { - counter = Counter.build() - .name("counter_total") - .help("Total number of requests.") - .labelNames("path") - .create(); + counter = + Counter.build() + .name("counter_total") + .help("Total number of requests.") + .labelNames("path") + .create(); - counterWithExemplars = Counter.build() - .name("counter_with_exemplars_total") - .help("Total number of requests.") - .labelNames("path") - .withExemplarSampler(new DefaultExemplarSampler(new MockSpanContextSupplier())) - .create(); + counterWithExemplars = + Counter.build() + .name("counter_with_exemplars_total") + .help("Total number of requests.") + .labelNames("path") + .withExemplarSampler(new DefaultExemplarSampler(new MockSpanContextSupplier())) + .create(); - counterWithoutExemplars = Counter.build() - .name("counter_without_exemplars_total") - .help("Total number of requests.") - .labelNames("path") - .withoutExemplars() - .create(); + counterWithoutExemplars = + Counter.build() + .name("counter_without_exemplars_total") + .help("Total number of requests.") + .labelNames("path") + .withoutExemplars() + .create(); } @Benchmark @@ -79,7 +81,7 @@ public String getSpanId() { @Override public boolean isSampled() { - return true; + return true; } } } diff --git a/benchmarks/src/archive/java/io/prometheus/client/benchmark/GaugeBenchmark.java b/benchmarks/src/archive/java/io/prometheus/client/benchmark/GaugeBenchmark.java index d088d280d..a8eb03c83 100644 --- a/benchmarks/src/archive/java/io/prometheus/client/benchmark/GaugeBenchmark.java +++ b/benchmarks/src/archive/java/io/prometheus/client/benchmark/GaugeBenchmark.java @@ -1,6 +1,7 @@ package io.prometheus.client.benchmark; import com.codahale.metrics.MetricRegistry; +import java.util.concurrent.TimeUnit; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Mode; @@ -13,8 +14,6 @@ import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; -import java.util.concurrent.TimeUnit; - @State(Scope.Benchmark) public class GaugeBenchmark { @@ -27,16 +26,16 @@ public class GaugeBenchmark { @Setup public void setup() { - prometheusSimpleGauge = io.prometheus.client.Gauge.build() - .name("name") - .help("some description..") - .labelNames("some", "group").create(); + prometheusSimpleGauge = + io.prometheus.client.Gauge.build() + .name("name") + .help("some description..") + .labelNames("some", "group") + .create(); prometheusSimpleGaugeChild = prometheusSimpleGauge.labels("test", "group"); - prometheusSimpleGaugeNoLabels = io.prometheus.client.Gauge.build() - .name("name") - .help("some description..") - .create(); + prometheusSimpleGaugeNoLabels = + io.prometheus.client.Gauge.build().name("name").help("some description..").create(); registry = new MetricRegistry(); codahaleCounter = registry.counter("name"); @@ -47,21 +46,21 @@ public void setup() { @BenchmarkMode({Mode.AverageTime}) @OutputTimeUnit(TimeUnit.NANOSECONDS) public void prometheusSimpleGaugeIncBenchmark() { - prometheusSimpleGauge.labels("test", "group").inc(); + prometheusSimpleGauge.labels("test", "group").inc(); } - + @Benchmark @BenchmarkMode({Mode.AverageTime}) @OutputTimeUnit(TimeUnit.NANOSECONDS) public void prometheusSimpleGaugeChildIncBenchmark() { - prometheusSimpleGaugeChild.inc(); + prometheusSimpleGaugeChild.inc(); } @Benchmark @BenchmarkMode({Mode.AverageTime}) @OutputTimeUnit(TimeUnit.NANOSECONDS) public void prometheusSimpleGaugeNoLabelsIncBenchmark() { - prometheusSimpleGaugeNoLabels.inc(); + prometheusSimpleGaugeNoLabels.inc(); } @Benchmark @@ -71,27 +70,26 @@ public void codahaleCounterIncBenchmark() { codahaleCounter.inc(); } - // Decrement. @Benchmark @BenchmarkMode({Mode.AverageTime}) @OutputTimeUnit(TimeUnit.NANOSECONDS) public void prometheusSimpleGaugeDecBenchmark() { - prometheusSimpleGauge.labels("test", "group").dec(); + prometheusSimpleGauge.labels("test", "group").dec(); } - + @Benchmark @BenchmarkMode({Mode.AverageTime}) @OutputTimeUnit(TimeUnit.NANOSECONDS) public void prometheusSimpleGaugeChildDecBenchmark() { - prometheusSimpleGaugeChild.dec(); + prometheusSimpleGaugeChild.dec(); } @Benchmark @BenchmarkMode({Mode.AverageTime}) @OutputTimeUnit(TimeUnit.NANOSECONDS) public void prometheusSimpleGaugeNoLabelsDecBenchmark() { - prometheusSimpleGaugeNoLabels.dec(); + prometheusSimpleGaugeNoLabels.dec(); } @Benchmark @@ -106,9 +104,9 @@ public void codahaleCounterDecBenchmark() { @BenchmarkMode({Mode.AverageTime}) @OutputTimeUnit(TimeUnit.NANOSECONDS) public void prometheusSimpleGaugeSetBenchmark() { - prometheusSimpleGauge.labels("test", "group").set(42); + prometheusSimpleGauge.labels("test", "group").set(42); } - + @Benchmark @BenchmarkMode({Mode.AverageTime}) @OutputTimeUnit(TimeUnit.NANOSECONDS) @@ -120,18 +118,19 @@ public void prometheusSimpleGaugeChildSetBenchmark() { @BenchmarkMode({Mode.AverageTime}) @OutputTimeUnit(TimeUnit.NANOSECONDS) public void prometheusSimpleGaugeNoLabelsSetBenchmark() { - prometheusSimpleGaugeNoLabels.set(42); + prometheusSimpleGaugeNoLabels.set(42); } public static void main(String[] args) throws RunnerException { - Options opt = new OptionsBuilder() - .include(GaugeBenchmark.class.getSimpleName()) - .warmupIterations(5) - .measurementIterations(4) - .threads(4) - .forks(1) - .build(); + Options opt = + new OptionsBuilder() + .include(GaugeBenchmark.class.getSimpleName()) + .warmupIterations(5) + .measurementIterations(4) + .threads(4) + .forks(1) + .build(); new Runner(opt).run(); } diff --git a/benchmarks/src/archive/java/io/prometheus/client/benchmark/SanitizeMetricNameBenchmark.java b/benchmarks/src/archive/java/io/prometheus/client/benchmark/SanitizeMetricNameBenchmark.java index d89e676e5..cb5f300ce 100644 --- a/benchmarks/src/archive/java/io/prometheus/client/benchmark/SanitizeMetricNameBenchmark.java +++ b/benchmarks/src/archive/java/io/prometheus/client/benchmark/SanitizeMetricNameBenchmark.java @@ -1,12 +1,12 @@ package io.prometheus.client.benchmark; -import com.codahale.metrics.MetricRegistry; +import io.prometheus.client.Collector; +import java.util.concurrent.TimeUnit; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Scope; -import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.runner.Runner; import org.openjdk.jmh.runner.RunnerException; @@ -14,23 +14,18 @@ import org.openjdk.jmh.runner.options.OptionsBuilder; import org.openjdk.jmh.runner.options.TimeValue; -import io.prometheus.client.Collector; - -import java.util.Random; -import java.util.concurrent.TimeUnit; - @State(Scope.Benchmark) public class SanitizeMetricNameBenchmark { @Benchmark - @BenchmarkMode({ Mode.AverageTime }) + @BenchmarkMode({Mode.AverageTime}) @OutputTimeUnit(TimeUnit.NANOSECONDS) public void sanitizeSanitizedName() { Collector.sanitizeMetricName("good_name"); } @Benchmark - @BenchmarkMode({ Mode.AverageTime }) + @BenchmarkMode({Mode.AverageTime}) @OutputTimeUnit(TimeUnit.NANOSECONDS) public void sanitizeNonSanitizedName() { Collector.sanitizeMetricName("9not_good_name!"); @@ -38,15 +33,16 @@ public void sanitizeNonSanitizedName() { public static void main(String[] args) throws RunnerException { - Options opt = new OptionsBuilder() - .include(SanitizeMetricNameBenchmark.class.getSimpleName()) - .warmupIterations(5) - .measurementIterations(4) - .measurementTime(TimeValue.seconds(1)) - .warmupTime(TimeValue.seconds(1)) - .threads(4) - .forks(1) - .build(); + Options opt = + new OptionsBuilder() + .include(SanitizeMetricNameBenchmark.class.getSimpleName()) + .warmupIterations(5) + .measurementIterations(4) + .measurementTime(TimeValue.seconds(1)) + .warmupTime(TimeValue.seconds(1)) + .threads(4) + .forks(1) + .build(); new Runner(opt).run(); } diff --git a/benchmarks/src/archive/java/io/prometheus/client/benchmark/SummaryBenchmark.java b/benchmarks/src/archive/java/io/prometheus/client/benchmark/SummaryBenchmark.java index 973106c68..2964b8ea8 100644 --- a/benchmarks/src/archive/java/io/prometheus/client/benchmark/SummaryBenchmark.java +++ b/benchmarks/src/archive/java/io/prometheus/client/benchmark/SummaryBenchmark.java @@ -1,6 +1,7 @@ package io.prometheus.client.benchmark; import com.codahale.metrics.MetricRegistry; +import java.util.concurrent.TimeUnit; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Mode; @@ -13,8 +14,6 @@ import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; -import java.util.concurrent.TimeUnit; - @State(Scope.Benchmark) public class SummaryBenchmark { @@ -30,27 +29,27 @@ public class SummaryBenchmark { @Setup public void setup() { - prometheusSimpleSummary = io.prometheus.client.Summary.build() - .name("name") - .help("some description..") - .labelNames("some", "group").create(); + prometheusSimpleSummary = + io.prometheus.client.Summary.build() + .name("name") + .help("some description..") + .labelNames("some", "group") + .create(); prometheusSimpleSummaryChild = prometheusSimpleSummary.labels("test", "group"); - prometheusSimpleSummaryNoLabels = io.prometheus.client.Summary.build() - .name("name") - .help("some description..") - .create(); + prometheusSimpleSummaryNoLabels = + io.prometheus.client.Summary.build().name("name").help("some description..").create(); - prometheusSimpleHistogram = io.prometheus.client.Histogram.build() - .name("name") - .help("some description..") - .labelNames("some", "group").create(); + prometheusSimpleHistogram = + io.prometheus.client.Histogram.build() + .name("name") + .help("some description..") + .labelNames("some", "group") + .create(); prometheusSimpleHistogramChild = prometheusSimpleHistogram.labels("test", "group"); - prometheusSimpleHistogramNoLabels = io.prometheus.client.Histogram.build() - .name("name") - .help("some description..") - .create(); + prometheusSimpleHistogramNoLabels = + io.prometheus.client.Histogram.build().name("name").help("some description..").create(); registry = new MetricRegistry(); codahaleHistogram = registry.histogram("name"); @@ -60,28 +59,28 @@ public void setup() { @BenchmarkMode({Mode.AverageTime}) @OutputTimeUnit(TimeUnit.NANOSECONDS) public void prometheusSimpleSummaryBenchmark() { - prometheusSimpleSummary.labels("test", "group").observe(1) ; + prometheusSimpleSummary.labels("test", "group").observe(1); } @Benchmark @BenchmarkMode({Mode.AverageTime}) @OutputTimeUnit(TimeUnit.NANOSECONDS) public void prometheusSimpleSummaryChildBenchmark() { - prometheusSimpleSummaryChild.observe(1); + prometheusSimpleSummaryChild.observe(1); } @Benchmark @BenchmarkMode({Mode.AverageTime}) @OutputTimeUnit(TimeUnit.NANOSECONDS) public void prometheusSimpleSummaryNoLabelsBenchmark() { - prometheusSimpleSummaryNoLabels.observe(1); + prometheusSimpleSummaryNoLabels.observe(1); } @Benchmark @BenchmarkMode({Mode.AverageTime}) @OutputTimeUnit(TimeUnit.NANOSECONDS) public void prometheusSimpleHistogramBenchmark() { - prometheusSimpleHistogram.labels("test", "group").observe(1) ; + prometheusSimpleHistogram.labels("test", "group").observe(1); } @Benchmark @@ -107,13 +106,14 @@ public void codahaleHistogramBenchmark() { public static void main(String[] args) throws RunnerException { - Options opt = new OptionsBuilder() - .include(SummaryBenchmark.class.getSimpleName()) - .warmupIterations(5) - .measurementIterations(4) - .threads(4) - .forks(1) - .build(); + Options opt = + new OptionsBuilder() + .include(SummaryBenchmark.class.getSimpleName()) + .warmupIterations(5) + .measurementIterations(4) + .threads(4) + .forks(1) + .build(); new Runner(opt).run(); } diff --git a/checkstyle.xml b/checkstyle.xml index fd483abfa..cac6be8d3 100644 --- a/checkstyle.xml +++ b/checkstyle.xml @@ -30,7 +30,7 @@ + default="checkstyle-suppressions.xml"/> @@ -44,7 +44,7 @@ + value="^package.*|^import.*|a href|href|http://|https://|ftp://|# HELP.*|jvm_runtime_info\{"/> @@ -64,9 +64,9 @@ + value="\\u00(09|0(a|A)|0(c|C)|0(d|D)|22|27|5(C|c))|\\(0(10|11|12|14|15|42|47)|134)"/> + value="Consider using special escape sequence instead of octal value or Unicode escaped value."/> @@ -81,15 +81,15 @@ + value="LITERAL_TRY, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE, LITERAL_SWITCH"/> + value="LITERAL_DO, LITERAL_ELSE, LITERAL_FOR, LITERAL_IF, LITERAL_WHILE"/> @@ -117,7 +117,7 @@ @@ -128,7 +128,7 @@ + value="WhitespaceAround: ''{0}'' is not followed by whitespace. Empty blocks may + only be represented as '{}' when not part of a multi-block statement (4.1.3)"/> + value="WhitespaceAround: ''{0}'' is not preceded with whitespace."/> @@ -148,7 +149,7 @@ @@ -184,76 +185,76 @@ + value="Type name ''{0}'' must match pattern ''{1}''."/> + value="Member name ''{0}'' must match pattern ''{1}''."/> + value="Logger fields must be named ''logger''."/> + value="Parameter name ''{0}'' must match pattern ''{1}''."/> + value="Lambda parameter name ''{0}'' must match pattern ''{1}''."/> + value="Catch parameter name ''{0}'' must match pattern ''{1}''."/> + value="Local variable name ''{0}'' must match pattern ''{1}''."/> + value="Pattern variable name ''{0}'' must match pattern ''{1}''."/> + value="Class type name ''{0}'' must match pattern ''{1}''."/> + value="Record type name ''{0}'' must match pattern ''{1}''."/> + value="Method type name ''{0}'' must match pattern ''{1}''."/> + value="Interface type name ''{0}'' must match pattern ''{1}''."/> + value="GenericWhitespace ''{0}'' is followed by whitespace."/> + value="GenericWhitespace ''{0}'' is preceded with whitespace."/> + value="GenericWhitespace ''{0}'' should followed by whitespace."/> + value="GenericWhitespace ''{0}'' is not preceded with whitespace."/> @@ -273,18 +274,18 @@ @@ -321,7 +322,7 @@ + value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF, VARIABLE_DEF"/> @@ -342,7 +343,7 @@ + value="Method name ''{0}'' must match pattern ''{1}''."/> + default="checkstyle-xpath-suppressions.xml"/> diff --git a/docs/README.md b/docs/README.md index 294c9a622..8ca147236 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,59 +1,60 @@ -Docs ----- +# Docs -This directory contains [hugo](https://gohugo.io) documentation to be published in Github pages. +This directory contains [hugo](https://gohugo.io) documentation to be published in GitHub pages. -Run Locally ------------ +## Run Locally -``` +```shell hugo server -D ``` This will serve the docs on [http://localhost:1313](http://localhost:1313). -Deploy to Github Pages ----------------------- +## Deploy to GitHub Pages -Changes to the `main` branch will be deployed automatically with Github actions. +Changes to the `main` branch will be deployed automatically with GitHub Actions. -Update Javadoc --------------- +## Update Javadoc -Javadoc are not checked-in to the Github repository. -They are generated on the fly by Github actions when the docs are updated. +Javadoc are not checked-in to the GitHub repository. +They are generated on the fly by GitHub Actions when the docs are updated. To view locally, run the following: -``` -# note that the 'compile' in the following command is necessary for Javadoc to detect the module structure +```shell +# note that the 'compile' in the following command is necessary for +# Javadoc to detect the module structure ./mvnw clean compile javadoc:javadoc javadoc:aggregate rm -r ./docs/static/api mv ./target/site/apidocs ./docs/static/api ``` -Github pages are in the `/client_java/` folder, so we link to `/client_java/api` rather than `/api`. +GitHub pages are in the `/client_java/` folder, so we link to `/client_java/api` rather than `/api`. To make JavaDoc work locally, create a link: -``` +```shell mkdir ./docs/static/client_java ln -s ../api ./docs/static/client_java/api ``` -Update Geekdocs ---------------- +## Update Geekdocs -The docs use the [Geekdocs](https://geekdocs.de/) theme. The theme is checked in to Github in the `./docs/themes/hugo-geekdoc/` folder. To update [Geekdocs](https://geekdocs.de/), remove the current folder and create a new one with the latest [release](https://github.com/thegeeklab/hugo-geekdoc/releases). There are no local modifications in `./docs/themes/hugo-geekdoc/`. +The docs use the [Geekdocs](https://geekdocs.de/) theme. The theme is checked in to GitHub in the +`./docs/themes/hugo-geekdoc/` folder. To update [Geekdocs](https://geekdocs.de/), remove the current +folder and create a new one with the +latest [release](https://github.com/thegeeklab/hugo-geekdoc/releases). There are no local +modifications in `./docs/themes/hugo-geekdoc/`. -Notes ------ +## Notes Here's how the initial `docs/` folder was set up: -``` +```shell hugo new site docs cd docs/ mkdir -p themes/hugo-geekdoc/ -curl -L https://github.com/thegeeklab/hugo-geekdoc/releases/download/v0.41.1/hugo-geekdoc.tar.gz | tar -xz -C themes/hugo-geekdoc/ --strip-components=1 +curl -L https://github.com/thegeeklab/hugo-geekdoc/releases/download/v0.41.1/hugo-geekdoc.tar.gz \ + | tar -xz -C themes/hugo-geekdoc/ --strip-components=1 ``` -Create the initial `hugo.toml` file as described in [https://geekdocs.de/usage/getting-started/](https://geekdocs.de/usage/getting-started/). +Create the initial `hugo.toml` file as described +in [https://geekdocs.de/usage/getting-started/](https://geekdocs.de/usage/getting-started/). diff --git a/docs/content/_index.md b/docs/content/_index.md index 9de934995..3b8966cf3 100644 --- a/docs/content/_index.md +++ b/docs/content/_index.md @@ -2,32 +2,54 @@ title: "client_java" --- -This is the documentation for the [Prometheus Java client library](https://github.com/prometheus/client_java) version 1.0.0 and higher. +This is the documentation for the +[Prometheus Java client library](https://github.com/prometheus/client_java) +version 1.0.0 and higher. The main new features of the 1.0.0 release are: -* **Prometheus native histograms:** Support for the new Prometheus histogram type. -* **OpenTelemetry Exporter:** Push metrics in OTLP format to an OpenTelemetry endpoint. -* **Runtime configuration:** Configure metrics, exporters, and more at runtime using a properties file or system properties. +- **Prometheus native histograms:** Support for the new Prometheus histogram type. +- **OpenTelemetry Exporter:** Push metrics in OTLP format to an OpenTelemetry endpoint. +- **Runtime configuration:** Configure metrics, exporters, and more at runtime using a properties + file or system properties. **Documentation and Examples** -In addition to this documentation page we created an [examples/](https://github.com/prometheus/client_java/tree/main/examples) directory with end-to-end scenarios (Docker compose) illustrating new features. +In addition to this documentation page we created an +[examples/](https://github.com/prometheus/client_java/tree/main/examples) directory with end-to-end +scenarios (Docker compose) illustrating new features. **Performance Benchmarks** -Initial performance benchmarks are looking great: All core metric types (including native histograms) allow concurrent updates, so if you instrument a performance critical Web service that utilizes all processor cores in parallel the metrics library will not introduce additional synchronization. See Javadoc comments in [benchmarks/](https://github.com/prometheus/client_java/tree/main/benchmarks) for benchmark results. +Initial performance benchmarks are looking great: All core metric types (including native +histograms) allow concurrent updates, so if you instrument a performance critical Web service +that utilizes all processor cores in parallel the metrics library will not introduce additional +synchronization. See Javadoc comments in +[benchmarks/](https://github.com/prometheus/client_java/tree/main/benchmarks) for benchmark results. **More Info** -The Grafana Labs Blog has a post [Introducing the Prometheus Java Client 1.0.0](https://grafana.com/blog/2023/09/27/introducing-the-prometheus-java-client-1.0.0/) with a good overview of the release. +The Grafana Labs Blog has a post +[Introducing the Prometheus Java Client 1.0.0](https://grafana.com/blog/2023/09/27/introducing-the-prometheus-java-client-1.0.0/) +with a good overview of the release. -There will also be a presentation at the [PromCon](https://promcon.io) conference on 29 Sep 2023. Tune in to the live stream on [https://promcon.io](https://promcon.io) or watch the recording on YouTube. +There will also be a presentation at the [PromCon](https://promcon.io) conference on 29 Sep 2023. +Tune in to the live stream on [https://promcon.io](https://promcon.io) +or watch the recording on YouTube. **For users of the 0.16.0 version and older** -Updating to the 1.0.0 version is a breaking change. However, there's a `prometheus-metrics-simpleclient-bridge` module available that allows you to use your existing simpleclient 0.16.0 metrics with the new 1.0.0 `PrometheusRegistry`. So you don't need to upgrade your instrumentation code, you can keep using your existing metrics. See the [compatibility > simpleclient](https://prometheus.github.io/client_java/migration/simpleclient/) in the menu on the left. +Updating to the 1.0.0 version is a breaking change. However, there's a +`prometheus-metrics-simpleclient-bridge` module available that allows you to use your existing +simpleclient 0.16.0 metrics with the new 1.0.0 `PrometheusRegistry`. +So you don't need to upgrade your instrumentation code, you can keep using your existing metrics. +See the +[compatibility > simpleclient](https://prometheus.github.io/client_java/migration/simpleclient/) +in the menu on the left. -The pre 1.0.0 code is now maintained on the [simpleclient](https://github.com/prometheus/client_java/tree/simpleclient) feature branch. +The pre 1.0.0 code is now maintained on the +[simpleclient](https://github.com/prometheus/client_java/tree/simpleclient) feature branch. -Not all `simpleclient` modules from 0.16.0 are included in the initial 1.0.0 release. Over the next couple of weeks we will work on porting the remaining modules, starting with `pushgateway` and the Servlet filter. +Not all `simpleclient` modules from 0.16.0 are included in the initial 1.0.0 release. +Over the next couple of weeks we will work on porting the remaining modules, +starting with `pushgateway` and the Servlet filter. diff --git a/docs/content/config/config.md b/docs/content/config/config.md index a7e57ac0d..a56b33da2 100644 --- a/docs/content/config/config.md +++ b/docs/content/config/config.md @@ -7,67 +7,76 @@ weight: 1 The Prometheus metrics library provides multiple options how to override configuration at runtime: -* Properties file -* System properties +- Properties file +- System properties Future releases will add more options, like configuration via environment variables. Example: -``` +```properties io.prometheus.exporter.httpServer.port = 9401 ``` -The property above changes the port for the [HTTPServer exporter]({{< relref "/exporters/httpserver.md" >}}) to _9401_. +The property above changes the port for the +[HTTPServer exporter]({{< relref "/exporters/httpserver.md" >}}) to _9401_. -* Properties file: Add the line above to the properties file. -* System properties: Use the command line parameter `-Dio.prometheus.exporter.httpServer.port=9401` when starting your application. +- Properties file: Add the line above to the properties file. +- System properties: Use the command line parameter `-Dio.prometheus.exporter.httpServer.port=9401` +- when starting your application. -Location of the Properties File -------------------------------- +## Location of the Properties File The properties file is searched in the following locations: -* `/prometheus.properties` in the classpath. This is for bundling a properties file with your application. -* System property `-Dprometheus.config=/path/to/prometheus.properties`. -* Environment variable `PROMETHEUS_CONFIG=/path/to/prometheus.properties`. - -Metrics Properties ------------------- - -| Name | Javadoc | Note | -| --------------- | --------|------| -| io.prometheus.metrics.exemplarsEnabled | [Counter.Builder.withExemplars()](/client_java/api/io/prometheus/metrics/core/metrics/Counter.Builder.html#withExemplars()) | (1) (2) | -| io.prometheus.metrics.histogramNativeOnly | [Histogram.Builder.nativeOnly()](/client_java/api/io/prometheus/metrics/core/metrics/Histogram.Builder.html#nativeOnly()) | (2) | -| io.prometheus.metrics.histogramClassicOnly | [Histogram.Builder.classicOnly()](/client_java/api/io/prometheus/metrics/core/metrics/Histogram.Builder.html#classicOnly()) | (2) | -| io.prometheus.metrics.histogramClassicUpperBounds | [Histogram.Builder.classicUpperBounds()](/client_java/api/io/prometheus/metrics/core/metrics/Histogram.Builder.html#classicUpperBounds(double...)) | (3) | -| io.prometheus.metrics.histogramNativeInitialSchema | [Histogram.Builder.nativeInitialSchema()](/client_java/api/io/prometheus/metrics/core/metrics/Histogram.Builder.html#nativeInitialSchema(int)) | | -| io.prometheus.metrics.histogramNativeMinZeroThreshold | [Histogram.Builder.nativeMinZeroThreshold()](/client_java/api/io/prometheus/metrics/core/metrics/Histogram.Builder.html#nativeMinZeroThreshold(double)) | | -| io.prometheus.metrics.histogramNativeMaxZeroThreshold | [Histogram.Builder.nativeMaxZeroThreshold()](/client_java/api/io/prometheus/metrics/core/metrics/Histogram.Builder.html#nativeMaxZeroThreshold(double)) | | -| io.prometheus.metrics.histogramNativeMaxNumberOfBuckets | [Histogram.Builder.nativeMaxNumberOfBuckets()](/client_java/api/io/prometheus/metrics/core/metrics/Histogram.Builder.html#nativeMaxNumberOfBuckets(int)) | | -| io.prometheus.metrics.histogramNativeResetDurationSeconds | [Histogram.Builder.nativeResetDuration()](/client_java/api/io/prometheus/metrics/core/metrics/Histogram.Builder.html#nativeResetDuration(long,java.util.concurrent.TimeUnit)) | | -| io.prometheus.metrics.summaryQuantiles | [Summary.Builder.quantile(double)](/client_java/api/io/prometheus/metrics/core/metrics/Summary.Builder.html#quantile(double)) | (4) | -| io.prometheus.metrics.summaryQuantileErrors | [Summary.Builder.quantile(double, double)](/client_java/api/io/prometheus/metrics/core/metrics/Summary.Builder.html#quantile(double,double)) | (5) | -| io.prometheus.metrics.summaryMaxAgeSeconds | [Summary.Builder.maxAgeSeconds()](/client_java/api/io/prometheus/metrics/core/metrics/Summary.Builder.html#maxAgeSeconds(long)) | | -| io.prometheus.metrics.summaryNumberOfAgeBuckets | [Summary.Builder.numberOfAgeBuckets()](/client_java/api/io/prometheus/metrics/core/metrics/Summary.Builder.html#numberOfAgeBuckets(int)) | | +- `/prometheus.properties` in the classpath. This is for bundling a properties file + with your application. +- System property `-Dprometheus.config=/path/to/prometheus.properties`. +- Environment variable `PROMETHEUS_CONFIG=/path/to/prometheus.properties`. + +## Metrics Properties + + + +| Name | Javadoc | Note | +| --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | +| io.prometheus.metrics.exemplarsEnabled | [Counter.Builder.withExemplars()]() | (1) (2) | +| io.prometheus.metrics.histogramNativeOnly | [Histogram.Builder.nativeOnly()]() | (2) | +| io.prometheus.metrics.histogramClassicOnly | [Histogram.Builder.classicOnly()]() | (2) | +| io.prometheus.metrics.histogramClassicUpperBounds | [Histogram.Builder.classicUpperBounds()]() | (3) | +| io.prometheus.metrics.histogramNativeInitialSchema | [Histogram.Builder.nativeInitialSchema()]() | | +| io.prometheus.metrics.histogramNativeMinZeroThreshold | [Histogram.Builder.nativeMinZeroThreshold()]() | | +| io.prometheus.metrics.histogramNativeMaxZeroThreshold | [Histogram.Builder.nativeMaxZeroThreshold()]() | | +| io.prometheus.metrics.histogramNativeMaxNumberOfBuckets | [Histogram.Builder.nativeMaxNumberOfBuckets()]() | | +| io.prometheus.metrics.histogramNativeResetDurationSeconds | [Histogram.Builder.nativeResetDuration()]() | | +| io.prometheus.metrics.summaryQuantiles | [Summary.Builder.quantile(double)]() | (4) | +| io.prometheus.metrics.summaryQuantileErrors | [Summary.Builder.quantile(double, double)]() | (5) | +| io.prometheus.metrics.summaryMaxAgeSeconds | [Summary.Builder.maxAgeSeconds()]() | | +| io.prometheus.metrics.summaryNumberOfAgeBuckets | [Summary.Builder.numberOfAgeBuckets()]() | | + + **Notes** -(1) _withExemplars()_ and _withoutExemplars()_ are available for all metric types, not just for counters
+(1) _withExemplars()_ and _withoutExemplars()_ are available for all metric types, +not just for counters
(2) Boolean value. Format: `property=true` or `property=false`.
(3) Comma-separated list. Example: `.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10`.
(4) Comma-separated list. Example: `0.5, 0.95, 0.99`.
-(5) Comma-separated list. If specified, the list must have the same length as `io.prometheus.metrics.summaryQuantiles`. Example: `0.01, 0.005, 0.005`. +(5) Comma-separated list. If specified, the list must have the same length as +`io.prometheus.metrics.summaryQuantiles`. Example: `0.01, 0.005, 0.005`. -There's one special feature about metric properties: You can set a property for one specific metric only by specifying the metric name. Example: Let's say you have a histogram named `latency_seconds`. +There's one special feature about metric properties: You can set a property for one specific +metric only by specifying the metric name. Example: +Let's say you have a histogram named `latency_seconds`. -``` +```properties io.prometheus.metrics.histogramClassicUpperBounds = 0.2, 0.4, 0.8, 1.0 ``` The line above sets histogram buckets for all histograms. However: -``` +```properties io.prometheus.metrics.latency_seconds.histogramClassicUpperBounds = 0.2, 0.4, 0.8, 1.0 ``` @@ -75,75 +84,95 @@ The line above sets histogram buckets only for the histogram named `latency_seco This works for all Metrics properties. -Exemplar Properties -------------------- +## Exemplar Properties + + + +| Name | Javadoc | Note | +| -------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---- | +| io.prometheus.exemplars.minRetentionPeriodSeconds | [ExemplarsProperties.getMinRetentionPeriodSeconds()]() | | +| io.prometheus.exemplars.maxRetentionPeriodSeconds | [ExemplarsProperties.getMaxRetentionPeriodSeconds()]() | | +| io.prometheus.exemplars.sampleIntervalMilliseconds | [ExemplarsProperties.getSampleIntervalMilliseconds()]() | | -| Name | Javadoc | Note | -| --------------- | --------|------| -| io.prometheus.exemplars.minRetentionPeriodSeconds | [ExemplarsProperties.getMinRetentionPeriodSeconds()](/client_java/api/io/prometheus/metrics/config/ExemplarsProperties.html#getMinRetentionPeriodSeconds()) | | -| io.prometheus.exemplars.maxRetentionPeriodSeconds | [ExemplarsProperties.getMaxRetentionPeriodSeconds()](/client_java/api/io/prometheus/metrics/config/ExemplarsProperties.html#getMaxRetentionPeriodSeconds()) | | -| io.prometheus.exemplars.sampleIntervalMilliseconds | [ExemplarsProperties.getSampleIntervalMilliseconds()](/client_java/api/io/prometheus/metrics/config/ExemplarsProperties.html#getSampleIntervalMilliseconds()) | | + -Exporter Properties -------------------- +## Exporter Properties -| Name | Javadoc | Note | -| --------------- | --------|------| -| io.prometheus.exporter.includeCreatedTimestamps | [ExporterProperties.getIncludeCreatedTimestamps()](/client_java/api/io/prometheus/metrics/config/ExporterProperties.html#getIncludeCreatedTimestamps()) | (1) | -| io.prometheus.exporter.exemplarsOnAllMetricTypes | [ExporterProperties.getExemplarsOnAllMetricTypes()](/client_java/api/io/prometheus/metrics/config/ExporterProperties.html#getExemplarsOnAllMetricTypes()) | (1) | + + +| Name | Javadoc | Note | +| ------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | ---- | +| io.prometheus.exporter.includeCreatedTimestamps | [ExporterProperties.getIncludeCreatedTimestamps()]() | (1) | +| io.prometheus.exporter.exemplarsOnAllMetricTypes | [ExporterProperties.getExemplarsOnAllMetricTypes()]() | (1) | + + (1) Boolean value, `true` or `false`. Default see Javadoc. -Exporter Filter Properties --------------------------- +## Exporter Filter Properties + + + +| Name | Javadoc | Note | +| -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---- | +| io.prometheus.exporter.filter.metricNameMustBeEqualTo | [ExporterFilterProperties.getAllowedMetricNames()]() | (1) | +| io.prometheus.exporter.filter.metricNameMustNotBeEqualTo | [ExporterFilterProperties.getExcludedMetricNames()]() | (2) | +| io.prometheus.exporter.filter.metricNameMustStartWith | [ExporterFilterProperties.getAllowedMetricNamePrefixes()]() | (3) | +| io.prometheus.exporter.filter.metricNameMustNotStartWith | [ExporterFilterProperties.getExcludedMetricNamePrefixes()]() | (4) | -| Name | Javadoc | Note | -| --------------- | --------|------| -| io.prometheus.exporter.filter.metricNameMustBeEqualTo | [ExporterFilterProperties.getAllowedMetricNames()](/client_java/api/io/prometheus/metrics/config/ExporterFilterProperties.html#getAllowedMetricNames()) | (1) | -| io.prometheus.exporter.filter.metricNameMustNotBeEqualTo | [ExporterFilterProperties.getExcludedMetricNames()](/client_java/api/io/prometheus/metrics/config/ExporterFilterProperties.html#getExcludedMetricNames()) | (2) | -| io.prometheus.exporter.filter.metricNameMustStartWith | [ExporterFilterProperties.getAllowedMetricNamePrefixes()](/client_java/api/io/prometheus/metrics/config/ExporterFilterProperties.html#getAllowedMetricNamePrefixes()) | (3) | -| io.prometheus.exporter.filter.metricNameMustNotStartWith | [ExporterFilterProperties.getExcludedMetricNamePrefixes()](/client_java/api/io/prometheus/metrics/config/ExporterFilterProperties.html#getExcludedMetricNamePrefixes()) | (4) | + (1) Comma sparated list of allowed metric names. Only these metrics will be exposed.
(2) Comma sparated list of excluded metric names. These metrics will not be exposed.
(3) Comma sparated list of prefixes. Only metrics starting with these prefixes will be exposed.
(4) Comma sparated list of prefixes. Metrics starting with these prefixes will not be exposed.
-Exporter HTTPServer Properties ------------------------------- - -| Name | Javadoc | Note | -| --------------- | --------|------| -| io.prometheus.exporter.httpServer.port | [HTTPServer.Builder.port()](/client_java/api/io/prometheus/metrics/exporter/httpserver/HTTPServer.Builder.html#port(int)) | | - -Exporter OpenTelemetry Properties ---------------------------------- - -| Name | Javadoc | Note | -| --------------- | --------|------| -| io.prometheus.exporter.opentelemetry.protocol | [OpenTelemetryExporter.Builder.protocol()](/client_java/api/io/prometheus/metrics/exporter/opentelemetry/OpenTelemetryExporter.Builder.html#protocol(java.lang.String)) | (1) | -| io.prometheus.exporter.opentelemetry.endpoint | [OpenTelemetryExporter.Builder.endpoint()](/client_java/api/io/prometheus/metrics/exporter/opentelemetry/OpenTelemetryExporter.Builder.html#endpoint(java.lang.String)) | | -| io.prometheus.exporter.opentelemetry.headers | [OpenTelemetryExporter.Builder.headers()](/client_java/api/io/prometheus/metrics/exporter/opentelemetry/OpenTelemetryExporter.Builder.html#header(java.lang.String,java.lang.String)) | (2) | -| io.prometheus.exporter.opentelemetry.intervalSeconds | [OpenTelemetryExporter.Builder.intervalSeconds()](/client_java/api/io/prometheus/metrics/exporter/opentelemetry/OpenTelemetryExporter.Builder.html#intervalSeconds(int)) | | -| io.prometheus.exporter.opentelemetry.timeoutSeconds | [OpenTelemetryExporter.Builder.timeoutSeconds()](/client_java/api/io/prometheus/metrics/exporter/opentelemetry/OpenTelemetryExporter.Builder.html#timeoutSeconds(int)) | | -| io.prometheus.exporter.opentelemetry.serviceName | [OpenTelemetryExporter.Builder.serviceName()](/client_java/api/io/prometheus/metrics/exporter/opentelemetry/OpenTelemetryExporter.Builder.html#serviceName(java.lang.String)) | | -| io.prometheus.exporter.opentelemetry.serviceNamespace | [OpenTelemetryExporter.Builder.serviceNamespace()](/client_java/api/io/prometheus/metrics/exporter/opentelemetry/OpenTelemetryExporter.Builder.html#serviceNamespace(java.lang.String)) | | -| io.prometheus.exporter.opentelemetry.serviceInstanceId | [OpenTelemetryExporter.Builder.serviceInstanceId()](/client_java/api/io/prometheus/metrics/exporter/opentelemetry/OpenTelemetryExporter.Builder.html#serviceInstanceId(java.lang.String)) | | -| io.prometheus.exporter.opentelemetry.serviceVersion | [OpenTelemetryExporter.Builder.serviceVersion()](/client_java/api/io/prometheus/metrics/exporter/opentelemetry/OpenTelemetryExporter.Builder.html#serviceVersion(java.lang.String)) | | -| io.prometheus.exporter.opentelemetry.resourceAttributes | [OpenTelemetryExporter.Builder.resourceAttributes()](/client_java/api/io/prometheus/metrics/exporter/opentelemetry/OpenTelemetryExporter.Builder.html#resourceAttribute(java.lang.String,java.lang.String)) | (3) | +## Exporter HTTPServer Properties + + + +| Name | Javadoc | Note | +| -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | ---- | +| io.prometheus.exporter.httpServer.port | [HTTPServer.Builder.port()]() | | + + + +## Exporter OpenTelemetry Properties + + + +| Name | Javadoc | Note | +| ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---- | +| io.prometheus.exporter.opentelemetry.protocol | [OpenTelemetryExporter.Builder.protocol()]() | (1) | +| io.prometheus.exporter.opentelemetry.endpoint | [OpenTelemetryExporter.Builder.endpoint()]() | | +| io.prometheus.exporter.opentelemetry.headers | [OpenTelemetryExporter.Builder.headers()]() | (2) | +| io.prometheus.exporter.opentelemetry.intervalSeconds | [OpenTelemetryExporter.Builder.intervalSeconds()]() | | +| io.prometheus.exporter.opentelemetry.timeoutSeconds | [OpenTelemetryExporter.Builder.timeoutSeconds()]() | | +| io.prometheus.exporter.opentelemetry.serviceName | [OpenTelemetryExporter.Builder.serviceName()]() | | +| io.prometheus.exporter.opentelemetry.serviceNamespace | [OpenTelemetryExporter.Builder.serviceNamespace()]() | | +| io.prometheus.exporter.opentelemetry.serviceInstanceId | [OpenTelemetryExporter.Builder.serviceInstanceId()]() | | +| io.prometheus.exporter.opentelemetry.serviceVersion | [OpenTelemetryExporter.Builder.serviceVersion()]() | | +| io.prometheus.exporter.opentelemetry.resourceAttributes | [OpenTelemetryExporter.Builder.resourceAttributes()]() | (3) | + + (1) Protocol can be `grpc` or `http/protobuf`.
(2) Format: `key1=value1,key2=value2`
(3) Format: `key1=value1,key2=value2` -Many of these attributes can alternatively be configured via OpenTelemetry environment variables, like `OTEL_EXPORTER_OTLP_ENDPOINT`. The Prometheus metrics library has support for OpenTelemetry environment variables. See Javadoc for details. +Many of these attributes can alternatively be configured via OpenTelemetry environment variables, +like `OTEL_EXPORTER_OTLP_ENDPOINT`. +The Prometheus metrics library has support for OpenTelemetry environment variables. +See Javadoc for details. + +## Exporter PushGateway Properties -Exporter PushGateway Properties -------------------------------- + -| Name | Javadoc | Note | -|--------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------|------| -| io.prometheus.exporter.pushgateway.address | [PushGateway.Builder.address()](/client_java/api/io/prometheus/metrics/exporter/pushgateway/PushGateway.Builder.html#address(java.lang.String)) | | -| io.prometheus.exporter.pushgateway.scheme | [PushGateway.Builder.scheme()](/client_java/api/io/prometheus/metrics/exporter/pushgateway/PushGateway.Builder.html#scheme(java.lang.String)) | | -| io.prometheus.exporter.pushgateway.job | [PushGateway.Builder.job()](/client_java/api/io/prometheus/metrics/exporter/pushgateway/PushGateway.Builder.html#job(java.lang.String)) | | +| Name | Javadoc | Note | +| ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------- | ---- | +| io.prometheus.exporter.pushgateway.address | [PushGateway.Builder.address()]() | | +| io.prometheus.exporter.pushgateway.scheme | [PushGateway.Builder.scheme()]() | | +| io.prometheus.exporter.pushgateway.job | [PushGateway.Builder.job()]() | | + diff --git a/docs/content/exporters/filter.md b/docs/content/exporters/filter.md index 32dc0a56d..01ac48e69 100644 --- a/docs/content/exporters/filter.md +++ b/docs/content/exporters/filter.md @@ -5,14 +5,16 @@ weight: 2 All exporters support a `name[]` URL parameter for querying only specific metric names. Examples: -* `/metrics?name[]=jvm_threads_current` will query the metric named `jvm_threads_current`. -* `/metrics?name[]=jvm_threads_current&name[]=jvm_threads_daemon` will query two metrics, `jvm_threads_current` and `jvm_threads_daemon`. +- `/metrics?name[]=jvm_threads_current` will query the metric named `jvm_threads_current`. +- `/metrics?name[]=jvm_threads_current&name[]=jvm_threads_daemon` will query two metrics, + `jvm_threads_current` and `jvm_threads_daemon`. -Add the following to the scape job configuration in `prometheus.yml` to make the Prometheus server send the `name[]` parameter: +Add the following to the scape job configuration in `prometheus.yml` +to make the Prometheus server send the `name[]` parameter: ```yaml params: - name[]: - - jvm_threads_current - - jvm_threads_daemon + name[]: + - jvm_threads_current + - jvm_threads_daemon ``` diff --git a/docs/content/exporters/formats.md b/docs/content/exporters/formats.md index 189d13d56..a6485c84c 100644 --- a/docs/content/exporters/formats.md +++ b/docs/content/exporters/formats.md @@ -5,23 +5,28 @@ weight: 1 All exporters the following exposition formats: -* OpenMetrics text format -* Prometheus text format -* Prometheus protobuf format +- OpenMetrics text format +- Prometheus text format +- Prometheus protobuf format Moreover, gzip encoding is supported for each of these formats. ## Scraping with a Prometheus server -The Prometheus server sends an `Accept` header to specify which format is requested. By default, the Prometheus server will scrape OpenMetrics text format with gzip encoding. If the Prometheus server is started with `--enable-feature=native-histograms`, it will scrape Prometheus protobuf format instead. +The Prometheus server sends an `Accept` header to specify which format is requested. By default, the +Prometheus server will scrape OpenMetrics text format with gzip encoding. If the Prometheus server +is started with `--enable-feature=native-histograms`, it will scrape Prometheus protobuf format +instead. ## Viewing with a Web Browser -If you view the `/metrics` endpoint with your Web browser you will see Prometheus text format. For quick debugging of the other formats, exporters provide a `debug` URL parameter: +If you view the `/metrics` endpoint with your Web browser you will see Prometheus text format. For +quick debugging of the other formats, exporters provide a `debug` URL parameter: -* `/metrics?debug=openmetrics`: View OpenMetrics text format. -* `/metrics?debug=text`: View Prometheus text format. -* `/metrics?debug=prometheus-protobuf`: View a text representation of the Prometheus protobuf format. +- `/metrics?debug=openmetrics`: View OpenMetrics text format. +- `/metrics?debug=text`: View Prometheus text format. +- `/metrics?debug=prometheus-protobuf`: View a text representation of the Prometheus protobuf + format. ## Exclude protobuf exposition format diff --git a/docs/content/exporters/httpserver.md b/docs/content/exporters/httpserver.md index e524b4cd1..4d0aab5f2 100644 --- a/docs/content/exporters/httpserver.md +++ b/docs/content/exporters/httpserver.md @@ -3,35 +3,41 @@ title: HTTPServer weight: 3 --- -The `HTTPServer` is a standalone server for exposing a metric endpoint. A minimal example application for `HTTPServer` can be found in the [examples](https://github.com/prometheus/client_java/tree/1.0.x/examples) directory. +The `HTTPServer` is a standalone server for exposing a metric endpoint. A minimal example +application for `HTTPServer` can be found in +the [examples](https://github.com/prometheus/client_java/tree/1.0.x/examples) directory. ```java HTTPServer server = HTTPServer.builder() - .port(9400) - .buildAndStart(); + .port(9400) + .buildAndStart(); ``` -By default, `HTTPServer` binds to any IP address, you can change this with [hostname()](/client_java/api/io/prometheus/metrics/exporter/httpserver/HTTPServer.Builder.html#hostname(java.lang.String)) or [inetAddress()](/client_java/api/io/prometheus/metrics/exporter/httpserver/HTTPServer.Builder.html#inetAddress(java.net.InetAddress)). +By default, `HTTPServer` binds to any IP address, you can change this with +[hostname()]() +or [inetAddress()](). `HTTPServer` is configured with three endpoints: -* `/metrics` for Prometheus scraping. -* `/-/healthy` for simple health checks. -* `/` the default handler is a static HTML page. +- `/metrics` for Prometheus scraping. +- `/-/healthy` for simple health checks. +- `/` the default handler is a static HTML page. -The default handler can be changed with [defaultHandler()](/client_java/api/io/prometheus/metrics/exporter/httpserver/HTTPServer.Builder.html#defaultHandler(com.sun.net.httpserver.HttpHandler)). +The default handler can be changed +with [defaultHandler()](). -Authentication and HTTPS ------------------------- +## Authentication and HTTPS -* [authenticator()](/client_java/api/io/prometheus/metrics/exporter/httpserver/HTTPServer.Builder.html#authenticator(com.sun.net.httpserver.Authenticator)) is for configuring authentication. -* [httpsConfigurator()](/client_java/api/io/prometheus/metrics/exporter/httpserver/HTTPServer.Builder.html#httpsConfigurator(com.sun.net.httpserver.HttpsConfigurator)) is for configuring HTTPS. +- [authenticator()]() + is for configuring authentication. +- [httpsConfigurator()]() + is for configuring HTTPS. -You can find an example of authentication and SSL in the [jmx_exporter](https://github.com/prometheus/jmx_exporter). +You can find an example of authentication and SSL in the +[jmx_exporter](https://github.com/prometheus/jmx_exporter). -Properties ----------- +## Properties See _config_ section (_todo_) on runtime configuration options. -* `io.prometheus.exporter.httpServer.port`: The port to bind to. +- `io.prometheus.exporter.httpServer.port`: The port to bind to. diff --git a/docs/content/exporters/pushgateway.md b/docs/content/exporters/pushgateway.md index 1ca2946b1..b4c531022 100644 --- a/docs/content/exporters/pushgateway.md +++ b/docs/content/exporters/pushgateway.md @@ -3,23 +3,28 @@ title: Pushgateway weight: 5 --- -The [Prometheus Pushgateway](https://github.com/prometheus/pushgateway) exists to allow ephemeral and batch jobs to expose their metrics to Prometheus. -Since these kinds of jobs may not exist long enough to be scraped, they can instead push their metrics to a Pushgateway. +The [Prometheus Pushgateway](https://github.com/prometheus/pushgateway) exists to allow ephemeral +and batch jobs to expose their metrics to Prometheus. +Since these kinds of jobs may not exist long enough to be scraped, they can instead push their +metrics to a Pushgateway. The Pushgateway then exposes these metrics to Prometheus. -The [PushGateway](/client_java/api/io/prometheus/metrics/exporter/pushgateway/PushGateway.html) Java class allows you to push metrics to a Prometheus Pushgateway. +The [PushGateway](/client_java/api/io/prometheus/metrics/exporter/pushgateway/PushGateway.html) Java +class allows you to push metrics to a Prometheus Pushgateway. -Example -------- +## Example {{< tabs "uniqueid" >}} {{< tab "Gradle" >}} -``` + +```groovy implementation 'io.prometheus:prometheus-metrics-core:1.3.0' implementation 'io.prometheus:prometheus-metrics-exporter-pushgateway:1.3.0' ``` + {{< /tab >}} {{< tab "Maven" >}} + ```xml io.prometheus @@ -32,6 +37,7 @@ implementation 'io.prometheus:prometheus-metrics-exporter-pushgateway:1.3.0' 1.3.0 ``` + {{< /tab >}} {{< /tabs >}} @@ -66,10 +72,10 @@ public class ExampleBatchJob { } ``` -Basic Auth ----------- +## Basic Auth -The [PushGateway](/client_java/api/io/prometheus/metrics/exporter/pushgateway/PushGateway.html) supports basic authentication. +The [PushGateway](/client_java/api/io/prometheus/metrics/exporter/pushgateway/PushGateway.html) +supports basic authentication. ```java PushGateway pushGateway = PushGateway.builder() @@ -80,10 +86,10 @@ PushGateway pushGateway = PushGateway.builder() The `PushGatewayTestApp` in `integration-tests/it-pushgateway` has a complete example of this. -Bearer token ----------- +## Bearer token -The [PushGateway](/client_java/api/io/prometheus/metrics/exporter/pushgateway/PushGateway.html) supports Bearer token authentication. +The [PushGateway](/client_java/api/io/prometheus/metrics/exporter/pushgateway/PushGateway.html) +supports Bearer token authentication. ```java PushGateway pushGateway = PushGateway.builder() @@ -94,11 +100,10 @@ PushGateway pushGateway = PushGateway.builder() The `PushGatewayTestApp` in `integration-tests/it-pushgateway` has a complete example of this. +## SSL -SSL ---- - -The [PushGateway](/client_java/api/io/prometheus/metrics/exporter/pushgateway/PushGateway.html) supports SSL. +The [PushGateway](/client_java/api/io/prometheus/metrics/exporter/pushgateway/PushGateway.html) +supports SSL. ```java PushGateway pushGateway = PushGateway.builder() @@ -109,10 +114,12 @@ PushGateway pushGateway = PushGateway.builder() However, this requires that the JVM can validate the server certificate. -If you want to skip certificate verification, you need to provide your own [HttpConnectionFactory](/client_java/api/io/prometheus/metrics/exporter/pushgateway/HttpConnectionFactory.html). +If you want to skip certificate verification, you need to provide your own +[HttpConnectionFactory](/client_java/api/io/prometheus/metrics/exporter/pushgateway/HttpConnectionFactory.html). The `PushGatewayTestApp` in `integration-tests/it-pushgateway` has a complete example of this. -Configuration Properties ------------------------- +## Configuration Properties -The [PushGateway](/client_java/api/io/prometheus/metrics/exporter/pushgateway/PushGateway.html) supports a couple of properties that can be configured at runtime. See [config](../../config/config). +The [PushGateway](/client_java/api/io/prometheus/metrics/exporter/pushgateway/PushGateway.html) +supports a couple of properties that can be configured at runtime. +See [config]({{< relref "../config/config.md" >}}). diff --git a/docs/content/exporters/servlet.md b/docs/content/exporters/servlet.md index 36a5161cf..93b870b1d 100644 --- a/docs/content/exporters/servlet.md +++ b/docs/content/exporters/servlet.md @@ -3,13 +3,16 @@ title: Servlet weight: 4 --- -The [PrometheusMetricsServlet](/client_java/api/io/prometheus/metrics/exporter/servlet/jakarta/PrometheusMetricsServlet.html) is a [Jakarta Servlet](https://jakarta.ee/specifications/servlet/) for exposing a metric endpoint. +The +[PrometheusMetricsServlet](/client_java/api/io/prometheus/metrics/exporter/servlet/jakarta/PrometheusMetricsServlet.html) +is a [Jakarta Servlet](https://jakarta.ee/specifications/servlet/) for exposing a metric endpoint. -web.xml -------- +## web.xml The old-school way of configuring a servlet is in a `web.xml` file: + + ```xml ``` -Programmatic ------------- - -Today, most Servlet applications use an embedded Servlet container and configure Servlets programmatically rather than via `web.xml`. -The API for that depends on the Servlet container. -The [examples](https://github.com/prometheus/client_java/tree/1.0.x/examples) directory has an example of an embedded [Tomcat](https://tomcat.apache.org/) container with the [PrometheusMetricsServlet](/client_java/api/io/prometheus/metrics/exporter/servlet/jakarta/PrometheusMetricsServlet.html) configured. + -Spring ------- +## Programmatic -You can use the [PrometheusMetricsServlet](/client_java/api/io/prometheus/metrics/exporter/servlet/jakarta/PrometheusMetricsServlet.html) in Spring applications. See [our Spring doc]({{< relref "spring.md" >}}). +Today, most Servlet applications use an embedded Servlet container and configure Servlets +programmatically rather than via `web.xml`. +The API for that depends on the Servlet container. +The [examples](https://github.com/prometheus/client_java/tree/1.0.x/examples) directory has an +example of an embedded +[Tomcat](https://tomcat.apache.org/) container with the +[PrometheusMetricsServlet](/client_java/api/io/prometheus/metrics/exporter/servlet/jakarta/PrometheusMetricsServlet.html) +configured. + +## Spring + +You can use +the [PrometheusMetricsServlet](/client_java/api/io/prometheus/metrics/exporter/servlet/jakarta/PrometheusMetricsServlet.html) +in Spring applications. +See [our Spring doc]({{< relref "spring.md" >}}). diff --git a/docs/content/exporters/spring.md b/docs/content/exporters/spring.md index 73e4b2549..fc0d946dd 100644 --- a/docs/content/exporters/spring.md +++ b/docs/content/exporters/spring.md @@ -3,33 +3,40 @@ title: Spring weight: 5 --- -Alternative: Use Spring's Built-in Metrics Library --------------------------------------------------- +## Alternative: Use Spring's Built-in Metrics Library -[Spring Boot](https://spring.io/projects/spring-boot) has a built-in metric library named [Micrometer](https://micrometer.io/), which supports Prometheus exposition format and can be set up in three simple steps: +[Spring Boot](https://spring.io/projects/spring-boot) has a built-in metric library named +[Micrometer](https://micrometer.io/), which supports Prometheus +exposition format and can be set up in three simple steps: 1. Add the `org.springframework.boot:spring-boot-starter-actuator` dependency. 2. Add the `io.micrometer:micrometer-registry-prometheus` as a _runtime_ dependency. -3. Enable the Prometheus endpoint by adding the line `management.endpoints.web.exposure.include=prometheus` to `application.properties`. +3. Enable the Prometheus endpoint by adding the line + `management.endpoints.web.exposure.include=prometheus` to `application.properties`. Note that Spring's default Prometheus endpoint is `/actuator/prometheus`, not `/metrics`. -In most cases the built-in Spring metrics library will work for you and you don't need the Prometheus Java library in Spring applications. +In most cases the built-in Spring metrics library will work for you and you don't need the +Prometheus Java library in Spring applications. -Use the Prometheus Metrics Library in Spring --------------------------------------------- +## Use the Prometheus Metrics Library in Spring -However, you may have your reasons why you want to use the Prometheus metrics library in Spring anyway. Maybe you want full support for all Prometheus metric types, or you want to use the new Prometheus native histograms. +However, you may have your reasons why you want to use the Prometheus metrics library in +Spring anyway. Maybe you want full support for all Prometheus metric types, +or you want to use the new Prometheus native histograms. -The easiest way to use the Prometheus metrics library in Spring is to configure the [PrometheusMetricsServlet](/client_java/api/io/prometheus/metrics/exporter/servlet/jakarta/PrometheusMetricsServlet.html) to expose metrics. +The easiest way to use the Prometheus metrics library in Spring is to configure the +[PrometheusMetricsServlet](/client_java/api/io/prometheus/metrics/exporter/servlet/jakarta/PrometheusMetricsServlet.html) +to expose metrics. Dependencies: -* `prometheus-metrics-core`: The core metrics library. -* `prometheus-metrics-exporter-servlet-jakarta`: For providing the `/metrics` endpoint. -* `prometheus-metrics-instrumentation-jvm`: Optional - JVM metrics +- `prometheus-metrics-core`: The core metrics library. +- `prometheus-metrics-exporter-servlet-jakarta`: For providing the `/metrics` endpoint. +- `prometheus-metrics-instrumentation-jvm`: Optional - JVM metrics -The following is the complete source code of a Spring Boot REST service using the Prometheus metrics library: +The following is the complete source code of a Spring Boot REST service using +the Prometheus metrics library: ```java import io.prometheus.metrics.core.metrics.Counter; @@ -46,35 +53,40 @@ import org.springframework.web.bind.annotation.RestController; @RestController public class DemoApplication { - private static final Counter requestCount = Counter.builder() - .name("requests_total") - .register(); - - public static void main(String[] args) { - SpringApplication.run(DemoApplication.class, args); - JvmMetrics.builder().register(); - } - - @GetMapping("/") - public String sayHello() throws InterruptedException { - requestCount.inc(); - return "Hello, World!\n"; - } - - @Bean - public ServletRegistrationBean createPrometheusMetricsEndpoint() { - return new ServletRegistrationBean<>(new PrometheusMetricsServlet(), "/metrics/*"); - } + private static final Counter requestCount = Counter.builder() + .name("requests_total") + .register(); + + public static void main(String[] args) { + SpringApplication.run(DemoApplication.class, args); + JvmMetrics.builder().register(); + } + + @GetMapping("/") + public String sayHello() throws InterruptedException { + requestCount.inc(); + return "Hello, World!\n"; + } + + @Bean + public ServletRegistrationBean createPrometheusMetricsEndpoint() { + return new ServletRegistrationBean<>(new PrometheusMetricsServlet(), "/metrics/*"); + } } ``` -The important part are the last three lines: They configure the [PrometheusMetricsServlet](/client_java/api/io/prometheus/metrics/exporter/servlet/jakarta/PrometheusMetricsServlet.html) to expose metrics on `/metrics`: +The important part are the last three lines: They configure the +[PrometheusMetricsServlet](/client_java/api/io/prometheus/metrics/exporter/servlet/jakarta/PrometheusMetricsServlet.html) +to expose metrics on `/metrics`: ```java + @Bean public ServletRegistrationBean createPrometheusMetricsEndpoint() { - return new ServletRegistrationBean<>(new PrometheusMetricsServlet(), "/metrics/*"); + return new ServletRegistrationBean<>(new PrometheusMetricsServlet(), "/metrics/*"); } ``` -The example provides a _Hello, world!_ endpoint on [http://localhost:8080](http://localhost:8080), and Prometheus metrics on [http://localhost:8080/metrics](http://localhost:8080/metrics). +The example provides a _Hello, world!_ endpoint on +[http://localhost:8080](http://localhost:8080), and Prometheus metrics on +[http://localhost:8080/metrics](http://localhost:8080/metrics). diff --git a/docs/content/getting-started/callbacks.md b/docs/content/getting-started/callbacks.md index b94033fc5..514d74c2a 100644 --- a/docs/content/getting-started/callbacks.md +++ b/docs/content/getting-started/callbacks.md @@ -3,11 +3,14 @@ title: Callbacks weight: 5 --- -The section on [metric types](../metric-types) showed how to use metrics that actively maintain their state. +The section on [metric types]({{< relref "metric-types.md" >}}) +showed how to use metrics that actively maintain their state. -This section shows how to create callback-based metrics, i.e. metrics that invoke a callback at scrape time to get the current values. +This section shows how to create callback-based metrics, i.e. metrics that invoke a callback +at scrape time to get the current values. -For example, let's assume we have two instances of a `Cache`, a `coldCache` and a `hotCache`. The following implements a callback-based `cache_size_bytes` metric: +For example, let's assume we have two instances of a `Cache`, a `coldCache` and a `hotCache`. +The following implements a callback-based `cache_size_bytes` metric: ```java Cache coldCache = new Cache(); @@ -27,7 +30,7 @@ GaugeWithCallback.builder() The resulting text format looks like this: -``` +```text # TYPE cache_size_bytes gauge # UNIT cache_size_bytes bytes # HELP cache_size_bytes Size of the cache in Bytes. @@ -35,15 +38,17 @@ cache_size_bytes{state="cold"} 78.0 cache_size_bytes{state="hot"} 83.0 ``` -Better examples of callback metrics can be found in the `prometheus-metrics-instrumentation-jvm` module. +Better examples of callback metrics can be found in the `prometheus-metrics-instrumentation-jvm` +module. The available callback metric types are: -* `GaugeWithCallback` for gauges. -* `CounterWithCallback` for counters. -* `SummaryWithCallback` for summaries. +- `GaugeWithCallback` for gauges. +- `CounterWithCallback` for counters. +- `SummaryWithCallback` for summaries. -The API for gauges and counters is very similar. For summaries the callback has a few more parameters, because it accepts a count, a sum, and quantiles: +The API for gauges and counters is very similar. For summaries the callback has a few more +parameters, because it accepts a count, a sum, and quantiles: ```java SummaryWithCallback.builder() diff --git a/docs/content/getting-started/labels.md b/docs/content/getting-started/labels.md index 5aeb5f215..d056a6ce6 100644 --- a/docs/content/getting-started/labels.md +++ b/docs/content/getting-started/labels.md @@ -5,7 +5,7 @@ weight: 3 The following shows an example of a Prometheus metric in text format: -``` +```text # HELP payments_total total number of payments # TYPE payments_total counter payments_total{status="error",type="paypal"} 1.0 @@ -13,12 +13,14 @@ payments_total{status="success",type="credit card"} 3.0 payments_total{status="success",type="paypal"} 2.0 ``` -The example shows a counter metric named `payments_total` with two labels: `status` and `type`. Each individual data point (each line in text format) is identified by the unique combination of its metric name and its label name/value pairs. +The example shows a counter metric named `payments_total` with two labels: `status` and `type`. +Each individual data point (each line in text format) is identified by the unique combination of +its metric name and its label name/value pairs. -Creating a Metric with Labels ------------------------------ +## Creating a Metric with Labels -Labels are supported for all metric types. We are using counters in this example, however the `labelNames()` and `labelValues()` methods are the same for other metric types. +Labels are supported for all metric types. We are using counters in this example, however the +`labelNames()` and `labelValues()` methods are the same for other metric types. The following code creates the counter above. @@ -34,10 +36,10 @@ counter.labelValues("paypal", "success").inc(2.0); counter.labelValues("paypal", "error").inc(1.0); ``` -The label names have to be specified when the metric is created and cannot change. The label values are created on demand when values are observed. +The label names have to be specified when the metric is created and cannot change. The label values +are created on demand when values are observed. -Creating a Metric without Labels --------------------------------- +## Creating a Metric without Labels Labels are optional. The following example shows a metric without labels: @@ -50,12 +52,13 @@ Counter counter = Counter.builder() counter.inc(3.0); ``` -Cardinality Explosion ---------------------- +## Cardinality Explosion -Each combination of label names and values will result in a new data point, i.e. a new line in text format. +Each combination of label names and values will result in a new data point, i.e. a new line in text +format. Therefore, a good label should have only a small number of possible values. -If you select labels with many possible values, like unique IDs or timestamps, you may end up with an enormous number of data points. +If you select labels with many possible values, like unique IDs or timestamps, +you may end up with an enormous number of data points. This is called cardinality explosion. Here's a bad example, don't do this: @@ -73,12 +76,12 @@ String timestamp = Long.toString(System.currentTimeMillis()); loginCount.labelValues(userId, timestamp).inc(); ``` -Initializing Label Values -------------------------- +## Initializing Label Values If you register a metric without labels, it will show up immediately with initial value of zero. -However, metrics with labels only show up after the label values are first used. In the example above +However, metrics with labels only show up after the label values are first used. In the example +above ```java counter.labelValues("paypal", "error").inc(); @@ -86,13 +89,14 @@ counter.labelValues("paypal", "error").inc(); The data point -``` +```text payments_total{status="error",type="paypal"} 1.0 ``` will jump from non-existent to value 1.0. You will never see it with value 0.0. -This is usually not an issue. However, if you find this annoying and want to see all possible label values from the start, you can initialize label values with `initLabelValues()` like this: +This is usually not an issue. However, if you find this annoying and want to see all possible label +values from the start, you can initialize label values with `initLabelValues()` like this: ```java Counter counter = Counter.builder() @@ -109,7 +113,7 @@ counter.initLabelValues("paypal", "error"); Now the four combinations will be visible from the start with initial value zero. -``` +```text # HELP payments_total total number of payments # TYPE payments_total counter payments_total{status="error",type="credit card"} 0.0 @@ -118,10 +122,10 @@ payments_total{status="success",type="credit card"} 0.0 payments_total{status="success",type="paypal"} 0.0 ``` -Expiring Unused Label Values ----------------------------- +## Expiring Unused Label Values -There is no automatic expiry of unused label values (yet). Once a set of label values is used, it will remain there forever. +There is no automatic expiry of unused label values (yet). Once a set of label values is used, it +will remain there forever. However, you can programmatically remove label values like this: @@ -130,8 +134,7 @@ counter.remove("paypal", "error"); counter.remove("paypal", "success"); ``` -Const Labels ------------- +## Const Labels If you have labels values that never change, you can specify them in the builder as `constLabels()`: @@ -144,6 +147,7 @@ Counter counter = Counter.builder() .register(); ``` -However, most use cases for `constLabels()` are better covered by target labels set by the scraping Prometheus server, +However, most use cases for `constLabels()` are better covered by target labels set by the scraping +Prometheus server, or by one specific metric (e.g. a `build_info` or a `machine_role` metric). See also -[target labels, not static scraped labels](https://prometheus.io/docs/instrumenting/writing_exporters/#target-labels-not-static-scraped-labels). +[target labels, not static scraped labels](https://prometheus.io/docs/instrumenting/writing_exporters/#target-labels-not-static-scraped-labels). diff --git a/docs/content/getting-started/metric-types.md b/docs/content/getting-started/metric-types.md index e10d51e9a..3bcda84fe 100644 --- a/docs/content/getting-started/metric-types.md +++ b/docs/content/getting-started/metric-types.md @@ -1,19 +1,25 @@ --- -title: 'Metric Types' +title: "Metric Types" weight: 4 --- -The Prometheus Java metrics library implements the metric types defined in the [OpenMetrics](https://openmetrics.io) standard: +The Prometheus Java metrics library implements the metric types defined in +the [OpenMetrics](https://openmetrics.io) standard: {{< toc >}} -Counter -------- +## Counter -Counter is the most common and useful metric type. Counters can only increase, but never decrease. In the Prometheus query language, the [rate()](https://prometheus.io/docs/prometheus/latest/querying/functions/#rate) function is often used for counters to calculate the average increase per second. +Counter is the most common and useful metric type. Counters can only increase, but never decrease. +In the Prometheus query language, +the [rate()](https://prometheus.io/docs/prometheus/latest/querying/functions/#rate) function is +often used for counters to calculate the average increase per second. {{< hint type=note >}} -Counter values do not need to be integers. In many cases counters represent a number of events (like the number of requests), and in that case the counter value is an integer. However, counters can also be used for something like "total time spent doing something" in which case the counter value is a floating point number. +Counter values do not need to be integers. In many cases counters represent a number of events (like +the number of requests), and in that case the counter value is an integer. However, counters can +also be used for something like "total time spent doing something" in which case the counter value +is a floating point number. {{< /hint >}} Here's an example of a counter: @@ -28,12 +34,14 @@ Counter serviceTimeSeconds = Counter.builder() serviceTimeSeconds.inc(Unit.millisToSeconds(200)); ``` -The resulting counter has the value `0.2`. As `SECONDS` is the standard time unit in Prometheus, the `Unit` utility class has methods to convert other time units to seconds. +The resulting counter has the value `0.2`. As `SECONDS` is the standard time unit in Prometheus, the +`Unit` utility class has methods to convert other time units to seconds. -As defined in [OpenMetrics](https://openmetrics.io/), counter metric names must have the `_total` suffix. If you create a counter without the `_total` suffix the suffix will be appended automatically. +As defined in [OpenMetrics](https://openmetrics.io/), counter metric names must have the `_total` +suffix. If you create a counter without the `_total` suffix the suffix will be appended +automatically. -Gauge ------ +## Gauge Gauges are current measurements, such as the current temperature in Celsius. @@ -48,27 +56,36 @@ Gauge temperature = Gauge.builder() temperature.labelValues("Berlin").set(22.3); ``` -Histogram ---------- +## Histogram -Histograms are for observing distributions, like latency distributions for HTTP services or the distribution of request sizes. -Unlike with counters and gauges, each histogram data point has a complex data structure representing different aspects of the distribution: +Histograms are for observing distributions, like latency distributions for HTTP services or the +distribution of request sizes. +Unlike with counters and gauges, each histogram data point has a complex data structure representing +different aspects of the distribution: -* Count: The total number of observations. -* Sum: The sum of all observed values, e.g. the total time spent serving requests. -* Buckets: The histogram buckets representing the distribution. +- Count: The total number of observations. +- Sum: The sum of all observed values, e.g. the total time spent serving requests. +- Buckets: The histogram buckets representing the distribution. Prometheus supports two flavors of histograms: -* Classic histograms: Bucket boundaries are explicitly defined when the histogram is created. -* Native histograms (exponential histograms): Infinitely many virtual buckets. +- Classic histograms: Bucket boundaries are explicitly defined when the histogram is created. +- Native histograms (exponential histograms): Infinitely many virtual buckets. -By default, histograms maintain both flavors. Which one is used depends on the scrape request from the Prometheus server. -* By default, the Prometheus server will scrape metrics in OpenMetrics format and get the classic histogram flavor. -* If the Prometheus server is started with `--enable-feature=native-histograms`, it will request metrics in Prometheus protobuf format and ingest the native histogram. -* If the Prometheus server is started with `--enable-feature=native-histogram` and the scrape config has the option `scrape_classic_histograms: true`, it will request metrics in Prometheus protobuf format and ingest both, the classic and the native flavor. This is great for migrating from classic histograms to native histograms. +By default, histograms maintain both flavors. Which one is used depends on the scrape request from +the Prometheus server. -See [examples/example-native-histogram](https://github.com/prometheus/client_java/tree/1.0.x/examples/example-native-histogram) for an example. +- By default, the Prometheus server will scrape metrics in OpenMetrics format and get the classic + histogram flavor. +- If the Prometheus server is started with `--enable-feature=native-histograms`, it will request + metrics in Prometheus protobuf format and ingest the native histogram. +- If the Prometheus server is started with `--enable-feature=native-histogram` and the scrape config + has the option `scrape_classic_histograms: true`, it will request metrics in Prometheus protobuf + format and ingest both, the classic and the native flavor. This is great for migrating from + classic histograms to native histograms. + +See [examples/example-native-histogram](https://github.com/prometheus/client_java/tree/1.0.x/examples/example-native-histogram) +for an example. ```java Histogram duration = Histogram.builder() @@ -83,17 +100,30 @@ long start = System.nanoTime(); duration.labelValues("GET", "/", "200").observe(Unit.nanosToSeconds(System.nanoTime() - start)); ``` -Histograms implement the [TimerApi](/client_java/api/io/prometheus/metrics/core/datapoints/TimerApi.html) interface, which provides convenience methods for measuring durations. +Histograms implement +the [TimerApi](/client_java/api/io/prometheus/metrics/core/datapoints/TimerApi.html) interface, +which provides convenience methods for measuring durations. -The histogram builder provides a lot of configuration for fine-tuning the histogram behavior. In most cases you don't need them, defaults are good. The following is an incomplete list showing the most important options: +The histogram builder provides a lot of configuration for fine-tuning the histogram behavior. In +most cases you don't need them, defaults are good. The following is an incomplete list showing the +most important options: -* `nativeOnly()` / `classicOnly()`: Create a histogram with one representation only. -* `classicBuckets(...)`: Set the classic bucket boundaries. Default buckets are `.005`, `.01`, `.025`, `.05`, `.1`, `.25`, `.5`, `1`, `2.5`, `5`, `and 10`. The default bucket boundaries are designed for measuring request durations in seconds. -* `nativeMaxNumberOfBuckets()`: Upper limit for the number of native histogram buckets. Default is 160. When the maximum is reached, the native histogram automatically reduces resolution to stay below the limit. +- `nativeOnly()` / `classicOnly()`: Create a histogram with one representation only. +- `classicBuckets(...)`: Set the classic bucket boundaries. Default buckets are `.005`, `.01`, + `.025`, `.05`, `.1`, `.25`, `.5`, `1`, `2.5`, `5`, `and 10`. The default bucket boundaries are + designed for measuring request durations in seconds. +- `nativeMaxNumberOfBuckets()`: Upper limit for the number of native histogram buckets. + Default is 160. When the maximum is reached, the native histogram automatically + reduces resolution to stay below the limit. -See Javadoc for [Histogram.Builder](/client_java/api/io/prometheus/metrics/core/metrics/Histogram.Builder.html) for a complete list of options. Some options can be configured at runtime, see [config](../../config/config). +See Javadoc +for [Histogram.Builder](/client_java/api/io/prometheus/metrics/core/metrics/Histogram.Builder.html) +for a complete list of options. Some options can be configured at runtime, +see [config]({{< relref "../config/config.md" >}}). -Histograms and summaries are both used for observing distributions. Therefore, the both implement the `DistributionDataPoint` interface. Using the `DistributionDataPoint` interface directly gives you the option to switch between histograms and summaries later with minimal code changes. +Histograms and summaries are both used for observing distributions. Therefore, the both implement +the `DistributionDataPoint` interface. Using the `DistributionDataPoint` interface directly gives +you the option to switch between histograms and summaries later with minimal code changes. Example of using the `DistributionDataPoint` interface for a histogram without labels: @@ -128,10 +158,10 @@ successfulEvents.observe(0.7); erroneousEvents.observe(0.2); ``` -Summary -------- +## Summary -Like histograms, summaries are for observing distributions. Each summary data point has a count and a sum like a histogram data point. +Like histograms, summaries are for observing distributions. Each summary data point has a count and +a sum like a histogram data point. However, rather than histogram buckets summaries maintain quantiles. ```java @@ -148,26 +178,37 @@ Summary requestLatency = Summary.builder() requestLatency.labelValues("ok").observe(2.7); ``` -The example above creates a summary with the 50th percentile (median), the 95th percentile, and the 99th percentile. Quantiles are optional, you can create a summary without quantiles if all you need is the count and the sum. +The example above creates a summary with the 50th percentile (median), the 95th percentile, and the +99th percentile. Quantiles are optional, you can create a summary without quantiles if all you need +is the count and the sum. {{< hint type=note >}} -The terms "percentile" and "quantile" mean the same thing. We use percentile when we express it as a number in [0, 100], and we use quantile when we express it as a number in [0.0, 1.0]. +The terms "percentile" and "quantile" mean the same thing. We use percentile when we express it as a +number in [0, 100], and we use quantile when we express it as a number in [0.0, 1.0]. {{< /hint >}} -The second parameter to `quantile()` is the maximum acceptable error. The call `.quantile(0.5, 0.01)` means that the actual quantile is somewhere in [0.49, 0.51]. Higher precision means higher memory usage. +The second parameter to `quantile()` is the maximum acceptable error. The call +`.quantile(0.5, 0.01)` means that the actual quantile is somewhere in [0.49, 0.51]. Higher precision +means higher memory usage. -The 0.0 quantile (min value) and the 1.0 quantile (max value) are special cases because you can get the precise values (error 0.0) with almost no memory overhead. +The 0.0 quantile (min value) and the 1.0 quantile (max value) are special cases because you can get +the precise values (error 0.0) with almost no memory overhead. -Quantile values are calculated based on a 5 minutes moving time window. The default time window can be changed with `maxAgeSeconds()` and `numberOfAgeBuckets()`. +Quantile values are calculated based on a 5 minutes moving time window. The default time window can +be changed with `maxAgeSeconds()` and `numberOfAgeBuckets()`. -Some options can be configured at runtime, see [config](../../config/config). +Some options can be configured at runtime, see [config]({{< relref "../config/config.md" >}}). -In general you should prefer histograms over summaries. The Prometheus query language has a function [histogram_quantile()](https://prometheus.io/docs/prometheus/latest/querying/functions/#histogram_quantile) for calculating quantiles from histograms. The advantage of query-time quantile calculation is that you can aggregate histograms before calculating the quantile. With summaries you must use the quantile with all its labels as it is. +In general you should prefer histograms over summaries. The Prometheus query language has a +function [histogram_quantile()](https://prometheus.io/docs/prometheus/latest/querying/functions/#histogram_quantile) +for calculating quantiles from histograms. The advantage of query-time quantile calculation is that +you can aggregate histograms before calculating the quantile. With summaries you must use the +quantile with all its labels as it is. -Info ----- +## Info -Info metrics are used to expose textual information which should not change during process lifetime. The value of an Info metric is always `1`. +Info metrics are used to expose textual information which should not change during process lifetime. +The value of an Info metric is always `1`. ```java Info info = Info.builder() @@ -185,20 +226,27 @@ info.setLabelValues(version, vendor, runtime); The info above looks as follows in OpenMetrics text format: -``` + + +```text # TYPE jvm_runtime info # HELP jvm_runtime JVM runtime info jvm_runtime_info{runtime="OpenJDK Runtime Environment",vendor="Oracle Corporation",version="1.8.0_382-b05"} 1 ``` -The example is taken from the `prometheus-metrics-instrumentation-jvm` module, so if you have `JvmMetrics` registered you should have a `jvm_runtime_info` metric out-of-the-box. + -As defined in [OpenMetrics](https://openmetrics.io/), info metric names must have the `_info` suffix. If you create a counter without the `_info` suffix the suffix will be appended automatically. +The example is taken from the `prometheus-metrics-instrumentation-jvm` module, so if you have +`JvmMetrics` registered you should have a `jvm_runtime_info` metric out-of-the-box. -StateSet --------- +As defined in [OpenMetrics](https://openmetrics.io/), info metric names must have the `_info` +suffix. If you create a counter without the `_info` suffix the suffix will be appended +automatically. -StateSet are a niche metric type in the OpenMetrics standard that is rarely used. The main use case is to signal which feature flags are enabled. +## StateSet + +StateSet are a niche metric type in the OpenMetrics standard that is rarely used. The main use case +is to signal which feature flags are enabled. ```java StateSet stateSet = StateSet.builder() @@ -214,16 +262,17 @@ stateSet.labelValues("dev").setTrue("feature2"); The OpenMetrics text format looks like this: -``` +```text # TYPE feature_flags stateset # HELP feature_flags Feature flags feature_flags{env="dev",feature_flags="feature1"} 0 feature_flags{env="dev",feature_flags="feature2"} 1 ``` -GaugeHistogram and Unknown --------------------------- +## GaugeHistogram and Unknown -These types are defined in the [OpenMetrics](https://openmetrics.io/) standard but not implemented in the `prometheus-metrics-core` API. +These types are defined in the [OpenMetrics](https://openmetrics.io/) standard but not implemented +in the `prometheus-metrics-core` API. However, `prometheus-metrics-model` implements the underlying data model for these types. -To use these types, you need to implement your own `Collector` where the `collect()` method returns an `UnknownSnapshot` or a `HistogramSnapshot` with `.gaugeHistogram(true)`. +To use these types, you need to implement your own `Collector` where the `collect()` method returns +an `UnknownSnapshot` or a `HistogramSnapshot` with `.gaugeHistogram(true)`. diff --git a/docs/content/getting-started/multi-target.md b/docs/content/getting-started/multi-target.md index 93e37d9af..16f85ac40 100644 --- a/docs/content/getting-started/multi-target.md +++ b/docs/content/getting-started/multi-target.md @@ -7,108 +7,118 @@ weight: 7 This is for the upcoming release 1.1.0. {{< /hint >}} -To support multi-target pattern you can create a custom collector overriding the purposed internal method in ExtendedMultiCollector +To support multi-target pattern you can create a custom collector overriding the purposed internal +method in ExtendedMultiCollector see SampleExtendedMultiCollector in io.prometheus.metrics.examples.httpserver + + ```java public class SampleExtendedMultiCollector extends ExtendedMultiCollector { - public SampleExtendedMultiCollector() { - super(); - } - - @Override - protected MetricSnapshots collectMetricSnapshots(PrometheusScrapeRequest scrapeRequest) { - - GaugeSnapshot.Builder gaugeBuilder = GaugeSnapshot.builder(); - gaugeBuilder.name("x_load").help("process load"); - - CounterSnapshot.Builder counterBuilder = CounterSnapshot.builder(); - counterBuilder.name(PrometheusNaming.sanitizeMetricName("x_calls_total")).help("invocations"); - - String[] targetNames = scrapeRequest.getParameterValues("target"); - String targetName; - String[] procs = scrapeRequest.getParameterValues("proc"); - if (targetNames == null || targetNames.length == 0) { - targetName = "defaultTarget"; - procs = null; //ignore procs param - } else { - targetName = targetNames[0]; - } - Builder counterDataPointBuilder = CounterSnapshot.CounterDataPointSnapshot.builder(); - io.prometheus.metrics.model.snapshots.GaugeSnapshot.GaugeDataPointSnapshot.Builder gaugeDataPointBuilder = GaugeSnapshot.GaugeDataPointSnapshot.builder(); - Labels lbls = Labels.of("target", targetName); - - if (procs == null || procs.length == 0) { - counterDataPointBuilder.labels(lbls.merge(Labels.of("proc", "defaultProc"))); - gaugeDataPointBuilder.labels(lbls.merge(Labels.of("proc", "defaultProc"))); - counterDataPointBuilder.value(70); - gaugeDataPointBuilder.value(Math.random()); - - counterBuilder.dataPoint(counterDataPointBuilder.build()); - gaugeBuilder.dataPoint(gaugeDataPointBuilder.build()); - - } else { - for (int i = 0; i < procs.length; i++) { - counterDataPointBuilder.labels(lbls.merge(Labels.of("proc", procs[i]))); - gaugeDataPointBuilder.labels(lbls.merge(Labels.of("proc", procs[i]))); - counterDataPointBuilder.value(Math.random()); - gaugeDataPointBuilder.value(Math.random()); - - counterBuilder.dataPoint(counterDataPointBuilder.build()); - gaugeBuilder.dataPoint(gaugeDataPointBuilder.build()); - } - } - Collection snaps = new ArrayList(); - snaps.add(counterBuilder.build()); - snaps.add(gaugeBuilder.build()); - MetricSnapshots msnaps = new MetricSnapshots(snaps); - return msnaps; - } - - public List getPrometheusNames() { - List names = new ArrayList(); - names.add("x_calls_total"); - names.add("x_load"); - return names; - } + public SampleExtendedMultiCollector() { + super(); + } + + @Override + protected MetricSnapshots collectMetricSnapshots(PrometheusScrapeRequest scrapeRequest) { + + GaugeSnapshot.Builder gaugeBuilder = GaugeSnapshot.builder(); + gaugeBuilder.name("x_load").help("process load"); + + CounterSnapshot.Builder counterBuilder = CounterSnapshot.builder(); + counterBuilder.name(PrometheusNaming.sanitizeMetricName("x_calls_total")).help("invocations"); + + String[] targetNames = scrapeRequest.getParameterValues("target"); + String targetName; + String[] procs = scrapeRequest.getParameterValues("proc"); + if (targetNames == null || targetNames.length == 0) { + targetName = "defaultTarget"; + procs = null; //ignore procs param + } else { + targetName = targetNames[0]; + } + Builder counterDataPointBuilder = CounterSnapshot.CounterDataPointSnapshot.builder(); + io.prometheus.metrics.model.snapshots.GaugeSnapshot.GaugeDataPointSnapshot.Builder gaugeDataPointBuilder = GaugeSnapshot.GaugeDataPointSnapshot.builder(); + Labels lbls = Labels.of("target", targetName); + + if (procs == null || procs.length == 0) { + counterDataPointBuilder.labels(lbls.merge(Labels.of("proc", "defaultProc"))); + gaugeDataPointBuilder.labels(lbls.merge(Labels.of("proc", "defaultProc"))); + counterDataPointBuilder.value(70); + gaugeDataPointBuilder.value(Math.random()); + + counterBuilder.dataPoint(counterDataPointBuilder.build()); + gaugeBuilder.dataPoint(gaugeDataPointBuilder.build()); + + } else { + for (int i = 0; i < procs.length; i++) { + counterDataPointBuilder.labels(lbls.merge(Labels.of("proc", procs[i]))); + gaugeDataPointBuilder.labels(lbls.merge(Labels.of("proc", procs[i]))); + counterDataPointBuilder.value(Math.random()); + gaugeDataPointBuilder.value(Math.random()); + + counterBuilder.dataPoint(counterDataPointBuilder.build()); + gaugeBuilder.dataPoint(gaugeDataPointBuilder.build()); + } + } + Collection snaps = new ArrayList(); + snaps.add(counterBuilder.build()); + snaps.add(gaugeBuilder.build()); + MetricSnapshots msnaps = new MetricSnapshots(snaps); + return msnaps; + } + + public List getPrometheusNames() { + List names = new ArrayList(); + names.add("x_calls_total"); + names.add("x_load"); + return names; + } } ``` -`PrometheusScrapeRequest` provides methods to access http-related infos from the request originally received by the endpoint + + + +`PrometheusScrapeRequest` provides methods to access http-related infos from the request originally +received by the endpoint ```java public interface PrometheusScrapeRequest { - String getRequestURI(); + String getRequestURI(); - String[] getParameterValues(String name); + String[] getParameterValues(String name); } ``` - Sample Prometheus scrape_config +```yaml +- job_name: "multi-target" + + # metrics_path defaults to '/metrics' + # scheme defaults to 'http'. + params: + proc: [proc1, proc2] + relabel_configs: + - source_labels: [__address__] + target_label: __param_target + - source_labels: [__param_target] + target_label: instance + - target_label: __address__ + replacement: localhost:9401 + static_configs: + - targets: ["target1", "target2"] ``` - - job_name: "multi-target" - - # metrics_path defaults to '/metrics' - # scheme defaults to 'http'. - params: - proc: [proc1, proc2] - relabel_configs: - - source_labels: [__address__] - target_label: __param_target - - source_labels: [__param_target] - target_label: instance - - target_label: __address__ - replacement: localhost:9401 - static_configs: - - targets: ["target1", "target2"] -``` + It's up to the specific MultiCollector implementation how to interpret the _target_ parameter. -It might be an explicit real target (i.e. via host name/ip address) or as an alias in some internal configuration. -The latter is more suitable when the MultiCollector implementation is a proxy (see https://github.com/prometheus/snmp_exporter) -In this case, invoking real target might require extra parameters (e.g. credentials) that might be complex to manage in Prometheus configuration +It might be an explicit real target (i.e. via host name/ip address) or as an alias in some internal +configuration. +The latter is more suitable when the MultiCollector implementation is a proxy ( +see ) +In this case, invoking real target might require extra parameters (e.g. credentials) that might be +complex to manage in Prometheus configuration (not considering the case where the proxy might become an "open relay") diff --git a/docs/content/getting-started/performance.md b/docs/content/getting-started/performance.md index 43e95c430..31b8de162 100644 --- a/docs/content/getting-started/performance.md +++ b/docs/content/getting-started/performance.md @@ -5,10 +5,10 @@ weight: 6 This section has tips on how to use the Prometheus Java client in high performance applications. -Specify Label Values Only Once ------------------------------- +## Specify Label Values Only Once -For high performance applications, we recommend to specify label values only once, and then use the data point directly. +For high performance applications, we recommend to specify label values only once, and then use the +data point directly. This applies to all metric types. Let's use a counter as an example here: @@ -26,7 +26,8 @@ You could increment the counter above like this: requestCount.labelValue("/", "200").inc(); ``` -However, the line above does not only increment the counter, it also looks up the label values to find the right data point. +However, the line above does not only increment the counter, it also looks up the label values to +find the right data point. In high performance applications you can optimize this by looking up the data point only once: @@ -40,16 +41,21 @@ Now, you can increment the data point directly, which is a highly optimized oper successfulCalls.inc(); ``` -Enable Only One Histogram Representation ----------------------------------------- +## Enable Only One Histogram Representation -By default, histograms maintain two representations under the hood: The classic histogram representation with static buckets, and the native histogram representation with dynamic buckets. +By default, histograms maintain two representations under the hood: The classic histogram +representation with static buckets, and the native histogram representation with dynamic buckets. -While this default provides the flexibility to scrape different representations at runtime, it comes at a cost, because maintaining multiple representations causes performance overhead. +While this default provides the flexibility to scrape different representations at runtime, it comes +at a cost, because maintaining multiple representations causes performance overhead. -In performance critical applications we recommend to use either the classic representation or the native representation, but not both. +In performance critical applications we recommend to use either the classic representation or the +native representation, but not both. -You can either configure this in code for each histogram by calling [classicOnly()](/client_java/api/io/prometheus/metrics/core/metrics/Histogram.Builder.html#classicOnly()) or [nativeOnly()](/client_java/api/io/prometheus/metrics/core/metrics/Histogram.Builder.html#nativeOnly()), or you use the corresponding [config options](../../config/config/). +You can either configure this in code for each histogram by +calling [classicOnly()]() +or [nativeOnly()](), +or you use the corresponding [config options]({{< relref "../config/config.md" >}}). One way to do this is with system properties in the command line when you start your application @@ -63,7 +69,10 @@ or java -Dio.prometheus.metrics.histogramNativeOnly=true my-app.jar ``` -If you don't want to add a command line parameter every time you start your application, you can add a `prometheus.properties` file to your classpath (put it in the `src/main/resources/` directory so that it gets packed into your JAR file). The `prometheus.properties` file should have the following line: +If you don't want to add a command line parameter every time you start your application, you can add +a `prometheus.properties` file to your classpath (put it in the `src/main/resources/` directory so +that it gets packed into your JAR file). The `prometheus.properties` file should have the following +line: ```properties io.prometheus.metrics.histogramClassicOnly=true @@ -75,4 +84,5 @@ or io.prometheus.metrics.histogramNativeOnly=true ``` -Future releases will add more configuration options, like support for configuration via environment variable`IO_PROMETHEUS_METRICS_HISTOGRAM_NATIVE_ONLY=true`. +Future releases will add more configuration options, like support for configuration via environment +variable`IO_PROMETHEUS_METRICS_HISTOGRAM_NATIVE_ONLY=true`. diff --git a/docs/content/getting-started/quickstart.md b/docs/content/getting-started/quickstart.md index 27b7c13f5..7974b26c9 100644 --- a/docs/content/getting-started/quickstart.md +++ b/docs/content/getting-started/quickstart.md @@ -7,22 +7,26 @@ This tutorial shows the quickest way to get started with the Prometheus Java met {{< toc >}} -# Dependencies +## Dependencies We use the following dependencies: -* `prometheus-metrics-core` is the actual metrics library. -* `prometheus-metrics-instrumentation-jvm` provides out-of-the-box JVM metrics. -* `prometheus-metrics-exporter-httpserver` is a standalone HTTP server for exposing Prometheus metrics. -{{< tabs "deps" >}} -{{< tab "Gradle" >}} -``` +- `prometheus-metrics-core` is the actual metrics library. +- `prometheus-metrics-instrumentation-jvm` provides out-of-the-box JVM metrics. +- `prometheus-metrics-exporter-httpserver` is a standalone HTTP server for exposing Prometheus + metrics. + {{< tabs "deps" >}} + {{< tab "Gradle" >}} + +```groovy implementation 'io.prometheus:prometheus-metrics-core:$version' implementation 'io.prometheus:prometheus-metrics-instrumentation-jvm:$version' implementation 'io.prometheus:prometheus-metrics-exporter-httpserver:$version' ``` + {{< /tab >}} {{< tab "Maven" >}} + ```xml io.prometheus @@ -40,25 +44,29 @@ implementation 'io.prometheus:prometheus-metrics-exporter-httpserver:$version' $version ``` + {{< /tab >}} {{< /tabs >}} -There are alternative exporters as well, for example if you are using a Servlet container like Tomcat or Undertow you might want to use `prometheus-exporter-servlet-jakarta` rather than a standalone HTTP server. +There are alternative exporters as well, for example if you are using a Servlet container like +Tomcat or Undertow you might want to use `prometheus-exporter-servlet-jakarta` rather than a +standalone HTTP server. {{< hint type=note >}} If you do not use the protobuf exposition format, you can -[exclude](../../exporters/formats#exclude-protobuf-exposition-format) +[exclude]({{< relref "quickstart.md#exclude-protobuf-exposition-format" >}}) it from the dependencies. {{< /hint >}} -# Dependency management +## Dependency management A Bill of Material -([BOM](https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#bill-of-materials-bom-poms)) +([BOM](https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#bill-of-materials-bom-poms)) ensures that versions of dependencies (including transitive ones) are aligned. -This is especially important when using Spring Boot, which manages some of the dependencies of the project. +This is especially important when using Spring Boot, which manages some of the dependencies of the +project. You should omit the version number of the dependencies in your build file if you are using a BOM. @@ -138,7 +146,7 @@ The following example shows how to import the Prometheus Java metrics BOMs using {{< /tab >}} {{< /tabs >}} -# Example Application +## Example Application ```java import io.prometheus.metrics.core.metrics.Counter; @@ -167,34 +175,38 @@ public class App { .port(9400) .buildAndStart(); - System.out.println("HTTPServer listening on port http://localhost:" + server.getPort() + "/metrics"); + System.out.println("HTTPServer listening on port http://localhost:" + + server.getPort() + "/metrics"); Thread.currentThread().join(); // sleep forever } } ``` -# Result +## Result -Run the application and view [http://localhost:9400/metrics](http://localhost:9400/metrics) with your browser to see the raw metrics. You should see the `my_count_total` metric as shown below plus the `jvm_` and `process_` metrics coming from `JvmMetrics`. +Run the application and view [http://localhost:9400/metrics](http://localhost:9400/metrics) with +your browser to see the raw metrics. You should see the `my_count_total` metric as shown below plus +the `jvm_` and `process_` metrics coming from `JvmMetrics`. -``` +```text # HELP my_count_total example counter # TYPE my_count_total counter my_count_total{status="error"} 1.0 my_count_total{status="ok"} 2.0 ``` -# Prometheus Configuration +## Prometheus Configuration -To scrape the metrics with a Prometheus server, download the latest Prometheus server [release](https://github.com/prometheus/prometheus/releases), and configure the `prometheus.yml` file as follows: +To scrape the metrics with a Prometheus server, download the latest Prometheus +server [release](https://github.com/prometheus/prometheus/releases), and configure the +`prometheus.yml` file as follows: ```yaml global: scrape_interval: 10s # short interval for manual testing scrape_configs: - - job_name: "java-example" static_configs: - targets: ["localhost:9400"] diff --git a/docs/content/getting-started/registry.md b/docs/content/getting-started/registry.md index 7ae1bcbff..afebbb304 100644 --- a/docs/content/getting-started/registry.md +++ b/docs/content/getting-started/registry.md @@ -3,10 +3,10 @@ title: Registry weight: 2 --- -In order to expose metrics, you need to register them with a `PrometheusRegistry`. We are using a counter as an example here, but the `register()` method is the same for all metric types. +In order to expose metrics, you need to register them with a `PrometheusRegistry`. We are using a +counter as an example here, but the `register()` method is the same for all metric types. -Registering a Metrics with the Default Registry ------------------------------------------------ +## Registering a Metrics with the Default Registry ```java Counter eventsTotal = Counter.builder() @@ -15,10 +15,10 @@ Counter eventsTotal = Counter.builder() .register(); // <-- implicitly uses PrometheusRegistry.defaultRegistry ``` -The `register()` call above builds the counter and registers it with the global static `PrometheusRegistry.defaultRegistry`. Using the default registry is recommended. +The `register()` call above builds the counter and registers it with the global static +`PrometheusRegistry.defaultRegistry`. Using the default registry is recommended. -Registering a Metrics with a Custom Registry --------------------------------------------- +## Registering a Metrics with a Custom Registry You can also register your metric with a custom registry: @@ -31,10 +31,10 @@ Counter eventsTotal = Counter.builder() .register(myRegistry); ``` -Registering a Metric with Multiple Registries ---------------------------------------------- +## Registering a Metric with Multiple Registries -As an alternative to calling `register()` directly, you can `build()` metrics without registering them, +As an alternative to calling `register()` directly, you can `build()` metrics without registering +them, and register them later: ```java @@ -51,7 +51,7 @@ Counter eventsTotal = Counter.builder() PrometheusRegistry.defaultRegistry.register(eventsTotal); // register the counter with a custom registry. -// This is ok, you can register a metric with multiple registries. +// This is OK, you can register a metric with multiple registries. PrometheusRegistry myRegistry = new PrometheusRegistry(); myRegistry.register(eventsTotal); @@ -60,10 +60,10 @@ myRegistry.register(eventsTotal); Custom registries are useful if you want to maintain different scopes of metrics, like a debug registry with a lot of metrics, and a default registry with only a few metrics. -IllegalArgumentException: Duplicate Metric Name in Registry ------------------------------------------------------------ +## IllegalArgumentException: Duplicate Metric Name in Registry -While it is ok to register the same metric with multiple registries, it is illegal to register the same metric name multiple times with the same registry. +While it is OK to register the same metric with multiple registries, it is illegal to register the +same metric name multiple times with the same registry. The following code will throw an `IllegalArgumentException`: ```java @@ -75,13 +75,13 @@ Counter eventsTotal1 = Counter.builder() Counter eventsTotal2 = Counter.builder() .name("events_total") .help("Total number of events") - .register(); // <-- IllegalArgumentException, because a metric with that name is already registered + .register(); // IllegalArgumentException, because a metric with that name is already registered ``` -Unregistering a Metric ----------------------- +## Unregistering a Metric -There is no automatic expiry of unused metrics (yet), once a metric is registered it will remain registered forever. +There is no automatic expiry of unused metrics (yet), once a metric is registered it will remain +registered forever. However, you can programmatically unregistered an obsolete metric like this: diff --git a/docs/content/instrumentation/caffeine.md b/docs/content/instrumentation/caffeine.md index dde7e561a..104a9b9fa 100644 --- a/docs/content/instrumentation/caffeine.md +++ b/docs/content/instrumentation/caffeine.md @@ -8,11 +8,14 @@ provided by caffeine `Cache` objects into prometheus metrics. {{< tabs "uniqueid" >}} {{< tab "Gradle" >}} -``` + +```groovy implementation 'io.prometheus:prometheus-metrics-instrumentation-caffeine:1.3.2' ``` + {{< /tab >}} {{< tab "Maven" >}} + ```xml io.prometheus @@ -20,17 +23,18 @@ implementation 'io.prometheus:prometheus-metrics-instrumentation-caffeine:1.3.2' 1.3.2 ``` + {{< /tab >}} {{< /tabs >}} In order to collect metrics: - * A single `CacheMetricsCollector` instance must be registered with the registry; - * Multiple `CacheMetricsCollector` instances cannot be registered with the same registry; - * The `Cache` object must be instantiated with the `recordStats()` option, and then added to the - `CacheMetricsCollector` instance with a unique name, which will be used as the value of the - `cache` label on the exported metrics; - * If the `recordStats` option is not set, most metrics will only return zero values; +- A single `CacheMetricsCollector` instance must be registered with the registry; + - Multiple `CacheMetricsCollector` instances cannot be registered with the same registry; +- The `Cache` object must be instantiated with the `recordStats()` option, and then added to the + `CacheMetricsCollector` instance with a unique name, which will be used as the value of the + `cache` label on the exported metrics; + - If the `recordStats` option is not set, most metrics will only return zero values; ```java var cache = Caffeine.newBuilder().recordStats().build(); @@ -48,12 +52,11 @@ does not exist, i.e. a constructor call `new CacheMetricsCollector()` is the onl All example metrics on this page will use the `mycache` label value. -Generic Cache Metrics ---------------------- +## Generic Cache Metrics For all cache instances, the following metrics will be available: -``` +```text # TYPE caffeine_cache_hit counter # HELP caffeine_cache_hit Cache hit totals caffeine_cache_hit_total{cache="mycache"} 10.0 @@ -71,14 +74,13 @@ caffeine_cache_eviction_total{cache="mycache"} 1.0 caffeine_cache_estimated_size{cache="mycache"} 5.0 ``` -Loading Cache Metrics ---------------------- +## Loading Cache Metrics If the cache is an instance of `LoadingCache`, i.e. it is built with a `loader` function that is managed by the cache library, then metrics for observing load time and load failures become available: -``` +```text # TYPE caffeine_cache_load_failure counter # HELP caffeine_cache_load_failure Cache load failures caffeine_cache_load_failure_total{cache="mycache"} 10.0 @@ -91,14 +93,14 @@ caffeine_cache_load_duration_seconds_count{cache="mycache"} 7.0 caffeine_cache_load_duration_seconds_sum{cache="mycache"} 0.0034 ``` -Weighted Cache Metrics ----------------------- +## Weighted Cache Metrics Two metrics exist for observability specifically of caches that define a `weigher`: -``` +```text # TYPE caffeine_cache_eviction_weight counter -# HELP caffeine_cache_eviction_weight Weight of evicted cache entries, doesn't include manually removed entries +# HELP caffeine_cache_eviction_weight Weight of evicted cache entries, doesn't include manually removed entries // editorconfig-checker-disable-line + caffeine_cache_eviction_weight_total{cache="mycache"} 5.0 # TYPE caffeine_cache_weighted_size gauge # HELP caffeine_cache_weighted_size Approximate accumulated weight of cache entries @@ -113,14 +115,14 @@ caffeine_cache_weighted_size{cache="mycache"} 30.0 Up to version 1.3.5 and older, the weighted metrics had a different behavior: - * `caffeine_cache_weighted_size` was not implemented; - * `caffeine_cache_eviction_weight` was exposed as a `gauge`; +- `caffeine_cache_weighted_size` was not implemented; +- `caffeine_cache_eviction_weight` was exposed as a `gauge`; It is possible to restore the behavior of version 1.3.5 and older, by either: - * Using the deprecated `new CacheMetricsCollector()` constructor; - * Using the flags provided on the `CacheMetricsCollector.Builder` object to opt-out of each of the - elements of the post-1.3.5 behavior: - * `builder.collectWeightedSize(false)` will disable collection of `caffeine_cache_weighted_size`; - * `builder.collectEvictionWeightAsCounter(false)` will expose `caffeine_cache_eviction_weight` as - a `gauge` metric; +- Using the deprecated `new CacheMetricsCollector()` constructor; +- Using the flags provided on the `CacheMetricsCollector.Builder` object to opt-out of each of the + elements of the post-1.3.5 behavior: + - `builder.collectWeightedSize(false)` will disable collection of `caffeine_cache_weighted_size`; + - `builder.collectEvictionWeightAsCounter(false)` will expose `caffeine_cache_eviction_weight` as + a `gauge` metric; diff --git a/docs/content/instrumentation/guava.md b/docs/content/instrumentation/guava.md index 33cadae97..ffc8f0ab2 100644 --- a/docs/content/instrumentation/guava.md +++ b/docs/content/instrumentation/guava.md @@ -8,11 +8,14 @@ provided by Guava `Cache` objects into prometheus metrics. {{< tabs "uniqueid" >}} {{< tab "Gradle" >}} -``` + +```groovy implementation 'io.prometheus:prometheus-metrics-instrumentation-guava:1.3.2' ``` + {{< /tab >}} {{< tab "Maven" >}} + ```xml io.prometheus @@ -20,17 +23,18 @@ implementation 'io.prometheus:prometheus-metrics-instrumentation-guava:1.3.2' 1.3.2 ``` + {{< /tab >}} {{< /tabs >}} In order to collect metrics: -* A single `CacheMetricsCollector` instance must be registered with the registry; - * Multiple `CacheMetricsCollector` instances cannot be registered with the same registry; -* The `Cache` object must be instantiated with the `recordStats()` option, and then added to the +- A single `CacheMetricsCollector` instance must be registered with the registry; + - Multiple `CacheMetricsCollector` instances cannot be registered with the same registry; +- The `Cache` object must be instantiated with the `recordStats()` option, and then added to the `CacheMetricsCollector` instance with a unique name, which will be used as the value of the `cache` label on the exported metrics; - * If the `recordStats` option is not set, most metrics will only return zero values; + - If the `recordStats` option is not set, most metrics will only return zero values; ```java var cache = CacheBuilder.newBuilder().recordStats().build(); @@ -41,12 +45,11 @@ cacheMetrics.addCache("mycache", cache); All example metrics on this page will use the `mycache` label value. -Generic Cache Metrics ---------------------- +## Generic Cache Metrics For all cache instances, the following metrics will be available: -``` +```text # TYPE guava_cache_hit counter # HELP guava_cache_hit Cache hit totals guava_cache_hit_total{cache="mycache"} 10.0 @@ -64,14 +67,13 @@ guava_cache_eviction_total{cache="mycache"} 1.0 guava_cache_size{cache="mycache"} 5.0 ``` -Loading Cache Metrics ---------------------- +## Loading Cache Metrics If the cache is an instance of `LoadingCache`, i.e. it is built with a `loader` function that is managed by the cache library, then metrics for observing load time and load failures become available: -``` +```text # TYPE guava_cache_load_failure counter # HELP guava_cache_load_failure Cache load failures guava_cache_load_failure_total{cache="mycache"} 10.0 diff --git a/docs/content/instrumentation/jvm.md b/docs/content/instrumentation/jvm.md index 4b6f90cc7..804c1b09b 100644 --- a/docs/content/instrumentation/jvm.md +++ b/docs/content/instrumentation/jvm.md @@ -3,15 +3,19 @@ title: JVM weight: 1 --- -The JVM instrumentation module provides a variety of out-of-the-box JVM and process metrics. To use it, add the following dependency: +The JVM instrumentation module provides a variety of out-of-the-box JVM and process metrics. To use +it, add the following dependency: {{< tabs "uniqueid" >}} {{< tab "Gradle" >}} -``` + +```groovy implementation 'io.prometheus:prometheus-metrics-instrumentation-jvm:1.0.0' ``` + {{< /tab >}} {{< tab "Maven" >}} + ```xml io.prometheus @@ -19,6 +23,7 @@ implementation 'io.prometheus:prometheus-metrics-instrumentation-jvm:1.0.0' 1.0.0 ``` + {{< /tab >}} {{< /tabs >}} @@ -28,16 +33,23 @@ Now, you can register the JVM metrics as follows: JvmMetrics.builder().register(); ``` -The line above will initialize all JVM metrics and register them with the default registry. If you want to register the metrics with a custom `PrometheusRegistry`, you can pass the registry as parameter to the `register()` call. +The line above will initialize all JVM metrics and register them with the default registry. If you +want to register the metrics with a custom `PrometheusRegistry`, you can pass the registry as +parameter to the `register()` call. -The sections below describe the individual classes providing JVM metrics. If you don't want to register all JVM metrics, you can register each of these classes individually rather than using `JvmMetrics`. +The sections below describe the individual classes providing JVM metrics. If you don't want to +register all JVM metrics, you can register each of these classes individually rather than using +`JvmMetrics`. -JVM Buffer Pool Metrics ------------------------ +## JVM Buffer Pool Metrics -JVM buffer pool metrics are provided by the [JvmBufferPoolMetrics](/client_java/api/io/prometheus/metrics/instrumentation/jvm/JvmBufferPoolMetrics.html) class. The data is coming from the [BufferPoolMXBean](https://docs.oracle.com/en/java/javase/21/docs/api/java.management/java/lang/management/BufferPoolMXBean.html). Example metrics: +JVM buffer pool metrics are provided by +the [JvmBufferPoolMetrics](/client_java/api/io/prometheus/metrics/instrumentation/jvm/JvmBufferPoolMetrics.html) +class. The data is coming from +the [BufferPoolMXBean](https://docs.oracle.com/en/java/javase/21/docs/api/java.management/java/lang/management/BufferPoolMXBean.html). +Example metrics: -``` +```text # HELP jvm_buffer_pool_capacity_bytes Bytes capacity of a given JVM buffer pool. # TYPE jvm_buffer_pool_capacity_bytes gauge jvm_buffer_pool_capacity_bytes{pool="direct"} 8192.0 @@ -52,12 +64,17 @@ jvm_buffer_pool_used_bytes{pool="direct"} 8192.0 jvm_buffer_pool_used_bytes{pool="mapped"} 0.0 ``` -JVM Class Loading Metrics -------------------------- +## JVM Class Loading Metrics -JVM class loading metrics are provided by the [JvmClassLoadingMetrics](/client_java/api/io/prometheus/metrics/instrumentation/jvm/JvmClassLoadingMetrics.html) class. The data is coming from the [ClassLoadingMXBean](https://docs.oracle.com/en/java/javase/21/docs/api/java.management/java/lang/management/ClassLoadingMXBean.html). Example metrics: +JVM class loading metrics are provided by +the [JvmClassLoadingMetrics](/client_java/api/io/prometheus/metrics/instrumentation/jvm/JvmClassLoadingMetrics.html) +class. The data is coming from +the [ClassLoadingMXBean](https://docs.oracle.com/en/java/javase/21/docs/api/java.management/java/lang/management/ClassLoadingMXBean.html). +Example metrics: -``` + + +```text # HELP jvm_classes_currently_loaded The number of classes that are currently loaded in the JVM # TYPE jvm_classes_currently_loaded gauge jvm_classes_currently_loaded 1109.0 @@ -69,23 +86,35 @@ jvm_classes_loaded_total 1109.0 jvm_classes_unloaded_total 0.0 ``` -JVM Compilation Metrics ------------------------ + -JVM compilation metrics are provided by the [JvmCompilationMetrics](/client_java/api/io/prometheus/metrics/instrumentation/jvm/JvmCompilationMetrics.html) class. The data is coming from the [CompilationMXBean](https://docs.oracle.com/en/java/javase/21/docs/api/java.management/java/lang/management/CompilationMXBean.html). Example metrics: +## JVM Compilation Metrics -``` +JVM compilation metrics are provided by +the [JvmCompilationMetrics](/client_java/api/io/prometheus/metrics/instrumentation/jvm/JvmCompilationMetrics.html) +class. The data is coming from +the [CompilationMXBean](https://docs.oracle.com/en/java/javase/21/docs/api/java.management/java/lang/management/CompilationMXBean.html). +Example metrics: + + + +```text # HELP jvm_compilation_time_seconds_total The total time in seconds taken for HotSpot class compilation # TYPE jvm_compilation_time_seconds_total counter jvm_compilation_time_seconds_total 0.152 ``` -JVM Garbage Collector Metrics ------------------------------ + -JVM garbage collector metrics are provided by the [JvmGarbageCollectorMetric](/client_java/api/io/prometheus/metrics/instrumentation/jvm/JvmGarbageCollectorMetrics.html) class. The data is coming from the [GarbageCollectorMXBean](https://docs.oracle.com/en/java/javase/21/docs/api/java.management/java/lang/management/GarbageCollectorMXBean.html). Example metrics: +## JVM Garbage Collector Metrics -``` +JVM garbage collector metrics are provided by +the [JvmGarbageCollectorMetric](/client_java/api/io/prometheus/metrics/instrumentation/jvm/JvmGarbageCollectorMetrics.html) +class. The data is coming from +the [GarbageCollectorMXBean](https://docs.oracle.com/en/java/javase/21/docs/api/java.management/java/lang/management/GarbageCollectorMXBean.html). +Example metrics: + +```text # HELP jvm_gc_collection_seconds Time spent in a given JVM garbage collector in seconds. # TYPE jvm_gc_collection_seconds summary jvm_gc_collection_seconds_count{gc="PS MarkSweep"} 0 @@ -94,12 +123,18 @@ jvm_gc_collection_seconds_count{gc="PS Scavenge"} 0 jvm_gc_collection_seconds_sum{gc="PS Scavenge"} 0.0 ``` -JVM Memory Metrics ------------------- +## JVM Memory Metrics -JVM memory metrics are provided by the [JvmMemoryMetrics](/client_java/api/io/prometheus/metrics/instrumentation/jvm/JvmMemoryMetrics.html) class. The data is coming from the [MemoryMXBean](https://docs.oracle.com/en/java/javase/21/docs/api/java.management/java/lang/management/MemoryMXBean.html) and the [MemoryPoolMXBean](https://docs.oracle.com/en/java/javase/21/docs/api/java.management/java/lang/management/MemoryPoolMXBean.html). Example metrics: +JVM memory metrics are provided by +the [JvmMemoryMetrics](/client_java/api/io/prometheus/metrics/instrumentation/jvm/JvmMemoryMetrics.html) +class. The data is coming from +the [MemoryMXBean](https://docs.oracle.com/en/java/javase/21/docs/api/java.management/java/lang/management/MemoryMXBean.html) +and the [MemoryPoolMXBean](https://docs.oracle.com/en/java/javase/21/docs/api/java.management/java/lang/management/MemoryPoolMXBean.html). +Example metrics: -``` + + +```text # HELP jvm_memory_committed_bytes Committed (bytes) of a given JVM memory area. # TYPE jvm_memory_committed_bytes gauge jvm_memory_committed_bytes{area="heap"} 4.98597888E8 @@ -173,12 +208,20 @@ jvm_memory_used_bytes{area="heap"} 9051232.0 jvm_memory_used_bytes{area="nonheap"} 1.1490688E7 ``` -JVM Memory Pool Allocation Metrics ----------------------------------- + -JVM memory pool allocation metrics are provided by the [JvmMemoryPoolAllocationMetrics](/client_java/api/io/prometheus/metrics/instrumentation/jvm/JvmMemoryPoolAllocationMetrics.html) class. The data is obtained by adding a [NotificationListener](https://docs.oracle.com/en/java/javase/21/docs/api/java.management/javax/management/NotificationListener.html) to the [GarbageCollectorMXBean](https://docs.oracle.com/en/java/javase/21/docs/api/java.management/java/lang/management/GarbageCollectorMXBean.html). Example metrics: +## JVM Memory Pool Allocation Metrics -``` +JVM memory pool allocation metrics are provided by +the [JvmMemoryPoolAllocationMetrics](/client_java/api/io/prometheus/metrics/instrumentation/jvm/JvmMemoryPoolAllocationMetrics.html) +class. The data is obtained by adding +a [NotificationListener](https://docs.oracle.com/en/java/javase/21/docs/api/java.management/javax/management/NotificationListener.html) +to the [GarbageCollectorMXBean](https://docs.oracle.com/en/java/javase/21/docs/api/java.management/java/lang/management/GarbageCollectorMXBean.html). +Example metrics: + + + +```text # HELP jvm_memory_pool_allocated_bytes_total Total bytes allocated in a given JVM memory pool. Only updated after GC, not continuously. # TYPE jvm_memory_pool_allocated_bytes_total counter jvm_memory_pool_allocated_bytes_total{pool="Code Cache"} 4336448.0 @@ -189,24 +232,36 @@ jvm_memory_pool_allocated_bytes_total{pool="PS Old Gen"} 1428888.0 jvm_memory_pool_allocated_bytes_total{pool="PS Survivor Space"} 4115280.0 ``` -JVM Runtime Info Metric ------------------------ + +## JVM Runtime Info Metric -The JVM runtime info metric is provided by the [JvmRuntimeInfoMetric](/client_java/api/io/prometheus/metrics/instrumentation/jvm/JvmRuntimeInfoMetric.html) class. The data is obtained via system properties and will not change throughout the lifetime of the application. Example metric: +The JVM runtime info metric is provided by +the [JvmRuntimeInfoMetric](/client_java/api/io/prometheus/metrics/instrumentation/jvm/JvmRuntimeInfoMetric.html) +class. The data is obtained via system properties and will not change throughout the lifetime of the +application. Example metric: -``` + + +```text # TYPE jvm_runtime info # HELP jvm_runtime JVM runtime info jvm_runtime_info{runtime="OpenJDK Runtime Environment",vendor="Oracle Corporation",version="1.8.0_382-b05"} 1 ``` -JVM Thread Metrics ------------------- + -JVM thread metrics are provided by the [JvmThreadsMetrics](/client_java/api/io/prometheus/metrics/instrumentation/jvm/JvmThreadsMetrics.html) class. The data is coming from the [ThreadMXBean](https://docs.oracle.com/en/java/javase/21/docs/api/java.management/java/lang/management/ThreadMXBean.html). Example metrics: +## JVM Thread Metrics -``` +JVM thread metrics are provided by +the [JvmThreadsMetrics](/client_java/api/io/prometheus/metrics/instrumentation/jvm/JvmThreadsMetrics.html) +class. The data is coming from +the [ThreadMXBean](https://docs.oracle.com/en/java/javase/21/docs/api/java.management/java/lang/management/ThreadMXBean.html). +Example metrics: + + + +```text # HELP jvm_threads_current Current thread count of a JVM # TYPE jvm_threads_current gauge jvm_threads_current 10.0 @@ -236,12 +291,23 @@ jvm_threads_state{state="UNKNOWN"} 0.0 jvm_threads_state{state="WAITING"} 3.0 ``` -Process Metrics ---------------- + -Process metrics are provided by the [ProcessMetrics](/client_java/api/io/prometheus/metrics/instrumentation/jvm/ProcessMetrics.html) class. The data is coming from the [OperatingSystemMXBean](https://docs.oracle.com/en/java/javase/21/docs/api/java.management/java/lang/management/OperatingSystemMXBean.html), the [RuntimeMXBean](https://docs.oracle.com/en/java/javase/21/docs/api/java.management/java/lang/management/RuntimeMXBean.html), and from the `/proc/self/status` file on Linux. The metrics with prefix `process_` are not specific to Java, but should be provided by every Prometheus client library, see [Process Metrics](https://prometheus.io/docs/instrumenting/writing_clientlibs/#process-metrics) in the Prometheus [writing client libraries](https://prometheus.io/docs/instrumenting/writing_clientlibs/#process-metrics) documentation. Example metrics: +## Process Metrics -``` +Process metrics are provided by +the [ProcessMetrics](/client_java/api/io/prometheus/metrics/instrumentation/jvm/ProcessMetrics.html) +class. The data is coming from +the [OperatingSystemMXBean](https://docs.oracle.com/en/java/javase/21/docs/api/java.management/java/lang/management/OperatingSystemMXBean.html), +the [RuntimeMXBean](https://docs.oracle.com/en/java/javase/21/docs/api/java.management/java/lang/management/RuntimeMXBean.html), +and from the `/proc/self/status` file on Linux. The metrics with prefix `process_` are not specific +to Java, but should be provided by every Prometheus client library, +see [Process Metrics](https://prometheus.io/docs/instrumenting/writing_clientlibs/#process-metrics) +in the +Prometheus [writing client libraries](https://prometheus.io/docs/instrumenting/writing_clientlibs/#process-metrics) +documentation. Example metrics: + +```text # HELP process_cpu_seconds_total Total user and system CPU time spent in seconds. # TYPE process_cpu_seconds_total counter process_cpu_seconds_total 1.63 diff --git a/docs/content/internals/model.md b/docs/content/internals/model.md index c1f1e7b6a..c54e79ee3 100644 --- a/docs/content/internals/model.md +++ b/docs/content/internals/model.md @@ -9,21 +9,36 @@ The illustration below shows the internal architecture of the Prometheus Java cl ## prometheus-metrics-core -This is the user facing metrics library, implementing the core metric types, like [Counter](/client_java/api/io/prometheus/metrics/core/metrics/Counter.html), [Gauge](/client_java/api/io/prometheus/metrics/core/metrics/Gauge.html) [Histogram](/client_java/api/io/prometheus/metrics/core/metrics/Histogram.html), and so on. - -All metric types implement the [Collector](/client_java/api/io/prometheus/metrics/model/registry/Collector.html) interface, i.e. they provide a [collect()](/client_java/api/io/prometheus/metrics/model/registry/Collector.html#collect()) method to produce snapshots. +This is the user facing metrics library, implementing the core metric types, +like [Counter](/client_java/api/io/prometheus/metrics/core/metrics/Counter.html), +[Gauge](/client_java/api/io/prometheus/metrics/core/metrics/Gauge.html) +[Histogram](/client_java/api/io/prometheus/metrics/core/metrics/Histogram.html), +and so on. + +All metric types implement +the [Collector](/client_java/api/io/prometheus/metrics/model/registry/Collector.html) interface, +i.e. they provide +a [collect()]() +method to produce snapshots. ## prometheus-metrics-model -The model is an internal library, implementing read-only immutable snapshots. These snapshots are returned by the [Collector.collect()](/client_java/api/io/prometheus/metrics/model/registry/Collector.html#collect()) method. +The model is an internal library, implementing read-only immutable snapshots. These snapshots are +returned by +the [Collector.collect()]() +method. -There is no need for users to use `prometheus-metrics-model` directly. Users should use the API provided by `prometheus-metrics-core`, which includes the core metrics as well as callback metrics. +There is no need for users to use `prometheus-metrics-model` directly. Users should use the API +provided by `prometheus-metrics-core`, which includes the core metrics as well as callback metrics. -However, maintainers of 3rd party metrics libraries might want to use `prometheus-metrics-model` if they want to add Prometheus exposition formats to their metrics library. +However, maintainers of third-party metrics libraries might want to use `prometheus-metrics-model` +if they want to add Prometheus exposition formats to their metrics library. ## Exporters and exposition formats -The `prometheus-metrics-exposition-formats` module converts snapshots to Prometheus exposition formats, like text format, OpenMetrics text format, or Prometheus protobuf format. - -The exporters like `prometheus-metrics-exporter-httpserver` or `prometheus-metrics-exporter-servlet-jakarta` use this to convert snapshots into the right format depending on the `Accept` header in the scrape request. +The `prometheus-metrics-exposition-formats` module converts snapshots to Prometheus exposition +formats, like text format, OpenMetrics text format, or Prometheus protobuf format. +The exporters like `prometheus-metrics-exporter-httpserver` or +`prometheus-metrics-exporter-servlet-jakarta` use this to convert snapshots into the right format +depending on the `Accept` header in the scrape request. diff --git a/docs/content/migration/simpleclient.md b/docs/content/migration/simpleclient.md index 27606dbb6..6d0580571 100644 --- a/docs/content/migration/simpleclient.md +++ b/docs/content/migration/simpleclient.md @@ -3,34 +3,53 @@ title: Simpleclient weight: 1 --- -The Prometheus Java client library 1.0.0 is a complete rewrite of the underlying data model, and is not backwards compatible with releases 0.16.0 and older for a variety of reasons: - -* The old data model was based on [OpenMetrics](https://openmetrics.io). Native histograms don't fit with the OpenMetrics model because they don't follow the "every sample has exactly one double value" paradigm. It was a lot cleaner to implement a dedicated `prometheus-metrics-model` than trying to fit native histograms into the existing OpenMetrics-based model. -* Version 0.16.0 and older has multiple Maven modules sharing the same Java package name. This is not supported by the Java module system. To support users of Java modules, we renamed all packages and made sure no package is reused across multiple Maven modules. - -Migration using the Simpleclient Bridge ---------------------------------------- - -Good news: Users of version 0.16.0 and older do not need to refactor all their instrumentation code to get started with 1.0.0. - -We provide a migration module for bridging the old simpleclient `CollectorRegistry` to the new `PrometheusRegistry`. +The Prometheus Java client library 1.0.0 is a complete rewrite of the underlying data model, and is +not backward +compatible with releases 0.16.0 and older for a variety of reasons: + +- The old data model was based on [OpenMetrics](https://openmetrics.io). Native histograms don't fit + with the + OpenMetrics model because they don't follow the "every sample has exactly one double value" + paradigm. It was a lot + cleaner to implement a dedicated `prometheus-metrics-model` than trying to fit native histograms + into the existing + OpenMetrics-based model. +- Version 0.16.0 and older has multiple Maven modules sharing the same Java package name. This is + not supported by the + Java module system. To support users of Java modules, we renamed all packages and made sure no + package is reused + across multiple Maven modules. + +## Migration using the Simpleclient Bridge + +Good news: Users of version 0.16.0 and older do not need to refactor all their instrumentation code +to get started with +1.0.0. + +We provide a migration module for bridging the old simpleclient `CollectorRegistry` to the new +`PrometheusRegistry`. To use the bridge, add the following dependency: {{< tabs "uniqueid" >}} {{< tab "Gradle" >}} -``` + +```groovy implementation 'io.prometheus:prometheus-metrics-simpleclient-bridge:1.0.0' ``` + {{< /tab >}} {{< tab "Maven" >}} + ```xml + - io.prometheus - prometheus-metrics-simpleclient-bridge - 1.0.0 + io.prometheus + prometheus-metrics-simpleclient-bridge + 1.0.0 ``` + {{< /tab >}} {{< /tabs >}} @@ -40,7 +59,9 @@ Then add the following to your code: SimpleclientCollector.builder().register(); ``` -This will make all metrics registered with simpleclient's `CollectorRegistry.defaultRegistry` available in the new `PrometheusRegistry.defaultRegistry`. +This will make all metrics registered with simpleclient's `CollectorRegistry.defaultRegistry` +available in the new +`PrometheusRegistry.defaultRegistry`. If you are using custom registries, you can specify them like this: @@ -49,23 +70,27 @@ CollectorRegistry simpleclientRegistry = ...; PrometheusRegistry prometheusRegistry = ...; SimpleclientCollector.builder() - .collectorRegistry(simpleclientRegistry) - .register(prometheusRegistry); + .collectorRegistry(simpleclientRegistry) + .register(prometheusRegistry); ``` -Refactoring the Instrumentation Code ------------------------------------- +## Refactoring the Instrumentation Code -If you decide to get rid of the old 0.16.0 dependencies and use 1.0.0 only, you need to refactor your code: +If you decide to get rid of the old 0.16.0 dependencies and use 1.0.0 only, you need to refactor +your code: Dependencies: -* `simpleclient` -> `prometheus-metrics-core` -* `simpleclient_hotspot` -> `prometheus-metrics-instrumentation-jvm` -* `simpleclient_httpserver` -> `prometheus-metrics-exporter-httpserver` -* `simpleclient_servlet_jakarta` -> `prometheus-metrics-exporter-servlet-jakarta` +- `simpleclient` -> `prometheus-metrics-core` +- `simpleclient_hotspot` -> `prometheus-metrics-instrumentation-jvm` +- `simpleclient_httpserver` -> `prometheus-metrics-exporter-httpserver` +- `simpleclient_servlet_jakarta` -> `prometheus-metrics-exporter-servlet-jakarta` -As long as you are using high-level metric API like `Counter`, `Gauge`, `Histogram`, and `Summary` converting code to the new API is relatively straightforward. You will need to adapt the package name and apply some minor changes like using `builder()` instead of `build()` or using `labelValues()` instead of `labels()`. +As long as you are using high-level metric API like `Counter`, `Gauge`, `Histogram`, and `Summary` +converting code to +the new API is relatively straightforward. You will need to adapt the package name and apply some +minor changes like +using `builder()` instead of `build()` or using `labelValues()` instead of `labels()`. Example of the old 0.16.0 API: @@ -73,10 +98,10 @@ Example of the old 0.16.0 API: import io.prometheus.client.Counter; Counter counter = Counter.build() - .name("test") - .help("test counter") - .labelNames("path") - .register(); + .name("test") + .help("test counter") + .labelNames("path") + .register(); counter.labels("/hello-world").inc(); ``` @@ -87,20 +112,31 @@ Example of the new 1.0.0 API: import io.prometheus.metrics.core.metrics.Counter; Counter counter = Counter.builder() - .name("test") - .help("test counter") - .labelNames("path") - .register(); + .name("test") + .help("test counter") + .labelNames("path") + .register(); counter.labelValues("/hello-world").inc(); ``` -Reasons why we changed the API: Changing the package names was a necessity because the previous package names were incompatible with the Java module system. However, renaming packages requires changing code anyway, so we decided to clean up some things. For example, the name `builder()` for a builder method is very common in the Java ecosystem, it's used in Spring, Lombok, and so on. So naming the method `builder()` makes the Prometheus library more aligned with the broader Java ecosystem. +Reasons why we changed the API: Changing the package names was a necessity because the previous +package names were +incompatible with the Java module system. However, renaming packages requires changing code anyway, +so we decided to +clean up some things. For example, the name `builder()` for a builder method is very common in the +Java ecosystem, it's +used in Spring, Lombok, and so on. So naming the method `builder()` makes the Prometheus library +more aligned with the +broader Java ecosystem. -If you are using the low level `Collector` API directly, you should have a look at the new callback metric types, see [/getting-started/callbacks/](../../getting-started/callbacks/). Chances are good that the new callback metrics have an easier way to achieve what you need than the old 0.16.0 code. +If you are using the low level `Collector` API directly, you should have a look at the new callback +metric types, +see [/getting-started/callbacks/]({{< relref "../getting-started/callbacks.md" >}}). Chances are +good that the new callback metrics have +an easier way to achieve what you need than the old 0.16.0 code. -JVM Metrics ------------ +## JVM Metrics Version 0.16.0 provided the `simpleclient_hotspot` module for exposing built-in JVM metrics: @@ -108,25 +144,30 @@ Version 0.16.0 provided the `simpleclient_hotspot` module for exposing built-in DefaultExports.initialize(); ``` -With version 1.0.0 these metrics moved to the `prometheus-metrics-instrumentation-jvm` module and are initialized as follows: +With version 1.0.0 these metrics moved to the `prometheus-metrics-instrumentation-jvm` module and +are initialized as follows: ```java JvmMetrics.builder().register(); ``` -A full list of the available JVM metrics can be found on [/instrumentation/jvm](../../instrumentation/jvm/). - -Most JVM metric names remained the same, except for a few cases where the old 0.16.0 metric names were not compliant with the [OpenMetrics](https://openmetrics.io) specification. OpenMetrics requires the unit to be a suffix, so we renamed metrics where the unit was in the middle of the metric name and moved the unit to the end of the metric name. The following metric names changed: - -* `jvm_memory_bytes_committed` -> `jvm_memory_committed_bytes` -* `jvm_memory_bytes_init` -> `jvm_memory_init_bytes` -* `jvm_memory_bytes_max` -> `jvm_memory_max_bytes` -* `jvm_memory_pool_bytes_committed` -> `jvm_memory_pool_committed_bytes` -* `jvm_memory_pool_bytes_init` -> `jvm_memory_pool_init_bytes` -* `jvm_memory_pool_bytes_max` -> `jvm_memory_pool_max_bytes` -* `jvm_memory_pool_bytes_used` -> `jvm_memory_pool_used_bytes` -* `jvm_memory_pool_collection_bytes_committed` -> `jvm_memory_pool_collection_committed_bytes` -* `jvm_memory_pool_collection_bytes_init` -> `jvm_memory_pool_collection_init_bytes` -* `jvm_memory_pool_collection_bytes_max` -> `jvm_memory_pool_collection_max_bytes` -* `jvm_memory_pool_collection_bytes_used` -> `jvm_memory_pool_collection_used_bytes` -* `jvm_info` -> `jvm_runtime_info` +A full list of the available JVM metrics can be found +on [/instrumentation/jvm]({{< relref "../instrumentation/jvm.md" >}}). + +Most JVM metric names remained the same, except for a few cases where the old 0.16.0 metric names +were not compliant with the [OpenMetrics](https://openmetrics.io) specification. OpenMetrics +requires the unit to be a suffix, so we renamed metrics where the unit was in the middle of the +metric name and moved the unit to the end of the metric name. The following metric names changed: + +- `jvm_memory_bytes_committed` -> `jvm_memory_committed_bytes` +- `jvm_memory_bytes_init` -> `jvm_memory_init_bytes` +- `jvm_memory_bytes_max` -> `jvm_memory_max_bytes` +- `jvm_memory_pool_bytes_committed` -> `jvm_memory_pool_committed_bytes` +- `jvm_memory_pool_bytes_init` -> `jvm_memory_pool_init_bytes` +- `jvm_memory_pool_bytes_max` -> `jvm_memory_pool_max_bytes` +- `jvm_memory_pool_bytes_used` -> `jvm_memory_pool_used_bytes` +- `jvm_memory_pool_collection_bytes_committed` -> `jvm_memory_pool_collection_committed_bytes` +- `jvm_memory_pool_collection_bytes_init` -> `jvm_memory_pool_collection_init_bytes` +- `jvm_memory_pool_collection_bytes_max` -> `jvm_memory_pool_collection_max_bytes` +- `jvm_memory_pool_collection_bytes_used` -> `jvm_memory_pool_collection_used_bytes` +- `jvm_info` -> `jvm_runtime_info` diff --git a/docs/content/otel/names.md b/docs/content/otel/names.md index 3d25dd3d4..2945d70e9 100644 --- a/docs/content/otel/names.md +++ b/docs/content/otel/names.md @@ -3,26 +3,40 @@ title: Names weight: 3 --- -OpenTelemetry naming conventions are different from Prometheus naming conventions. The mapping from OpenTelemetry metric names to Prometheus metric names is well defined in OpenTelemetry's [Prometheus and OpenMetrics Compatibility](https://opentelemetry.io/docs/specs/otel/compatibility/prometheus_and_openmetrics/) spec, and the [OpenTelemetryExporter](/client_java/api/io/prometheus/metrics/exporter/opentelemetry/OpenTelemetryExporter.html) implements that specification. +OpenTelemetry naming conventions are different from Prometheus naming conventions. The mapping from +OpenTelemetry metric names to Prometheus metric names is well defined in +OpenTelemetry's [Prometheus and OpenMetrics Compatibility](https://opentelemetry.io/docs/specs/otel/compatibility/prometheus_and_openmetrics/) +spec, and +the [OpenTelemetryExporter](/client_java/api/io/prometheus/metrics/exporter/opentelemetry/OpenTelemetryExporter.html) +implements that specification. -The goal is, if you set up a pipeline as illustrated below, you will see the same metric names in the Prometheus server as if you had exposed Prometheus metrics directly. +The goal is, if you set up a pipeline as illustrated below, you will see the same metric names in +the Prometheus server as if you had exposed Prometheus metrics directly. -![Image of a with the Prometheus client library pushing metrics to an OpenTelemetry collector](/client_java/images/otel-pipeline.png) +![Image of a with the Prometheus client library pushing metrics to an OpenTelemetry collector](/client_java/images/otel-pipeline.png) The main steps when converting OpenTelemetry metric names to Prometheus metric names are: -* Replace dots with underscores. -* If the metric has a unit, append the unit to the metric name, like `_seconds`. -* If the metric type has a suffix, append it, like `_total` for counters. +- Replace dots with underscores. +- If the metric has a unit, append the unit to the metric name, like `_seconds`. +- If the metric type has a suffix, append it, like `_total` for counters. -Dots in Metric and Label Names ------------------------------- +## Dots in Metric and Label Names -OpenTelemetry defines not only a line protocol, but also _semantic conventions_, i.e. standardized metric and label names. For example, OpenTelemetry's [Semantic Conventions for HTTP Metrics](https://opentelemetry.io/docs/specs/otel/metrics/semantic_conventions/http-metrics/) say that if you instrument an HTTP server with OpenTelemetry, you must have a histogram named `http.server.duration`. +OpenTelemetry defines not only a line protocol, but also _semantic conventions_, i.e. standardized +metric and label names. For example, +OpenTelemetry's [Semantic Conventions for HTTP Metrics](https://opentelemetry.io/docs/specs/otel/metrics/semantic_conventions/http-metrics/) +say that if you instrument an HTTP server with OpenTelemetry, you must have a histogram named +`http.server.duration`. -Most names defined in semantic conventions use dots. In the Prometheus server, the dot is an illegal character (this might change in future versions of the Prometheus server). +Most names defined in semantic conventions use dots. In the Prometheus server, the dot is an illegal +character (this might change in future versions of the Prometheus server). -The Prometheus Java client library allows dots, so that you can use metric names and label names as defined in OpenTelemetry's semantic conventions. -The dots will automatically be replaced with underscores if you expose metrics in Prometheus format, but you will see the original names with dots if you push your metrics in OpenTelemetry format. +The Prometheus Java client library allows dots, so that you can use metric names and label names as +defined in OpenTelemetry's semantic conventions. +The dots will automatically be replaced with underscores if you expose metrics in Prometheus format, +but you will see the original names with dots if you push your metrics in OpenTelemetry format. -That way, you can use OTel-compliant metric and label names today when instrumenting your application with the Prometheus Java client, and you are prepared in case your monitoring backend adds features in the future that require OTel-compliant instrumentation. +That way, you can use OTel-compliant metric and label names today when instrumenting your +application with the Prometheus Java client, and you are prepared in case your monitoring backend +adds features in the future that require OTel-compliant instrumentation. diff --git a/docs/content/otel/otlp.md b/docs/content/otel/otlp.md index ea39f178f..2a6f8da9b 100644 --- a/docs/content/otel/otlp.md +++ b/docs/content/otel/otlp.md @@ -3,19 +3,23 @@ title: OTLP weight: 1 --- -The Prometheus Java client library allows you to push metrics to an OpenTelemetry endpoint using the OTLP protocol. +The Prometheus Java client library allows you to push metrics to an OpenTelemetry endpoint using the +OTLP protocol. -![Image of a with the Prometheus client library pushing metrics to an OpenTelemetry collector](/client_java/images/otel-pipeline.png) +![Image of a with the Prometheus client library pushing metrics to an OpenTelemetry collector](/client_java/images/otel-pipeline.png) To implement this, you need to include `prometheus-metrics-exporter` as a dependency {{< tabs "uniqueid" >}} {{< tab "Gradle" >}} -``` + +```groovy implementation 'io.prometheus:prometheus-metrics-exporter-opentelemetry:1.0.0' ``` + {{< /tab >}} {{< tab "Maven" >}} + ```xml io.prometheus @@ -23,6 +27,7 @@ implementation 'io.prometheus:prometheus-metrics-exporter-opentelemetry:1.0.0' 1.0.0 ``` + {{< /tab >}} {{< /tabs >}} @@ -34,8 +39,23 @@ OpenTelemetryExporter.builder() .buildAndStart(); ``` -By default, the `OpenTelemetryExporter` will push metrics every 60 seconds to `localhost:4317` using `grpc` protocol. You can configure this in code using the [OpenTelemetryExporter.Builder](/client_java/api/io/prometheus/metrics/exporter/opentelemetry/OpenTelemetryExporter.Builder.html), or at runtime via [`io.prometheus.exporter.opentelemetry.*`](../../config/config/#exporter-opentelemetry-properties) properties. - -In addition to the Prometheus Java client configuration, the exporter also recognizes standard OpenTelemetry configuration. For example, you can set the [OTEL_EXPORTER_OTLP_METRICS_ENDPOINT](https://opentelemetry.io/docs/concepts/sdk-configuration/otlp-exporter-configuration/#otel_exporter_otlp_metrics_endpoint) environment variable to configure the endpoint. The Javadoc for [OpenTelemetryExporter.Builder](/client_java/api/io/prometheus/metrics/exporter/opentelemetry/OpenTelemetryExporter.Builder.html) shows which settings have corresponding OTel configuration. The intended use case is that if you attach the [OpenTelemetry Java agent](https://github.com/open-telemetry/opentelemetry-java-instrumentation/) for tracing, and use the Prometheus Java client for metrics, it is sufficient to configure the OTel agent because the Prometheus library will pick up the same configuration. - -The [examples/example-exporter-opentelemetry](https://github.com/prometheus/client_java/tree/main/examples/example-exporter-opentelemetry) folder has a docker compose with a complete end-to-end example, including a Java app, the OTel collector, and a Prometheus server. +By default, the `OpenTelemetryExporter` will push metrics every 60 seconds to `localhost:4317` using +`grpc` protocol. You can configure this in code using +the [OpenTelemetryExporter.Builder](/client_java/api/io/prometheus/metrics/exporter/opentelemetry/OpenTelemetryExporter.Builder.html), +or at runtime via [`io.prometheus.exporter.opentelemetry.*`]({{< relref "../config/config.md#exporter-opentelemetry-properties" >}}) +properties. + +In addition to the Prometheus Java client configuration, the exporter also recognizes standard +OpenTelemetry configuration. For example, you can set +the [OTEL_EXPORTER_OTLP_METRICS_ENDPOINT](https://opentelemetry.io/docs/concepts/sdk-configuration/otlp-exporter-configuration/#otel_exporter_otlp_metrics_endpoint) +environment variable to configure the endpoint. The Javadoc +for [OpenTelemetryExporter.Builder](/client_java/api/io/prometheus/metrics/exporter/opentelemetry/OpenTelemetryExporter.Builder.html) +shows which settings have corresponding OTel configuration. The intended use case is that if you +attach the +[OpenTelemetry Java agent](https://github.com/open-telemetry/opentelemetry-java-instrumentation/) +for tracing, and use the Prometheus Java client for metrics, it is sufficient to configure the OTel +agent because the Prometheus library will pick up the same configuration. + +The [examples/example-exporter-opentelemetry](https://github.com/prometheus/client_java/tree/main/examples/example-exporter-opentelemetry) +folder has a docker compose with a complete end-to-end example, including a Java app, the OTel +collector, and a Prometheus server. diff --git a/docs/content/otel/tracing.md b/docs/content/otel/tracing.md index 406575a63..0e3fb72fa 100644 --- a/docs/content/otel/tracing.md +++ b/docs/content/otel/tracing.md @@ -3,9 +3,21 @@ title: Tracing weight: 2 --- -OpenTelemetry’s [vision statement](https://github.com/open-telemetry/community/blob/main/mission-vision-values.md) says that [telemetry should be loosely coupled](https://github.com/open-telemetry/community/blob/main/mission-vision-values.md#telemetry-should-be-loosely-coupled), allowing end users to pick and choose from the pieces they want without having to bring in the rest of the project, too. In that spirit, you might choose to instrument your Java application with the Prometheus Java client library for metrics, and attach the [OpenTelemetry Java agent](https://github.com/open-telemetry/opentelemetry-java-instrumentation/) to get distributed tracing. +OpenTelemetry’s +[vision statement](https://github.com/open-telemetry/community/blob/main/mission-vision-values.md) +says that +[telemetry should be loosely coupled](https://github.com/open-telemetry/community/blob/main/mission-vision-values.md#telemetry-should-be-loosely-coupled), +allowing end users to pick and choose from the pieces they want without having to bring in the rest +of the project, too. In that spirit, you might choose to instrument your Java application with the +Prometheus Java client library for metrics, and attach the +[OpenTelemetry Java agent](https://github.com/open-telemetry/opentelemetry-java-instrumentation/) +to get distributed tracing. -First, if you attach the [OpenTelemetry Java agent](https://github.com/open-telemetry/opentelemetry-java-instrumentation/) you might want to turn off OTel's built-in metrics, because otherwise you get metrics from both the Prometheus Java client library and the OpenTelemetry agent (technically it's no problem to get both metrics, it's just not a common use case). +First, if you attach the +[OpenTelemetry Java agent](https://github.com/open-telemetry/opentelemetry-java-instrumentation/) +you might want to turn off OTel's built-in metrics, because otherwise you get metrics from both the +Prometheus Java client library and the OpenTelemetry agent (technically it's no problem to get both +metrics, it's just not a common use case). ```bash # This will tell the OpenTelemetry agent not to send metrics, just traces and logs. @@ -18,19 +30,34 @@ Now, start your application with the OpenTelemetry Java agent attached for trace java -javaagent:path/to/opentelemetry-javaagent.jar -jar myapp.jar ``` -With the OpenTelemetry Java agent attached, the Prometheus client library will do a lot of magic under the hood. +With the OpenTelemetry Java agent attached, the Prometheus client library will do a lot of magic +under the hood. -* `service.name` and `service.instance.id` are used in OpenTelemetry to uniquely identify a service instance. The Prometheus client library will automatically use the same `service.name` and `service.instance.id` as the agent when pushing metrics in OpenTelemetry format. That way the monitoring backend will see that the metrics and the traces are coming from the same instance. -* Exemplars are added automatically if a Prometheus metric is updated in the context of a distributed OpenTelemetry trace. -* If a Span is used as an Exemplar, the Span is marked with the Span attribute `exemplar="true"`. This can be used in the OpenTelemetry's sampling policy to make sure Exemplars are always sampled. +- `service.name` and `service.instance.id` are used in OpenTelemetry to uniquely identify a service + instance. The Prometheus client library will automatically use the same `service.name` and + `service.instance.id` as the agent when pushing metrics in OpenTelemetry format. That way the + monitoring backend will see that the metrics and the traces are coming from the same instance. +- Exemplars are added automatically if a Prometheus metric is updated in the context of a + distributed OpenTelemetry trace. +- If a Span is used as an Exemplar, the Span is marked with the Span attribute `exemplar="true"`. + This can be used in the OpenTelemetry's sampling policy to make sure Exemplars are always sampled. -Here's more context on the `exemplar="true"` Span attribute: Many users of tracing libraries don't keep 100% of their trace data, because traces are very repetitive. It is very common to sample only 10% of traces and discard 90%. However, this can be an issue with Exemplars: In 90% of the cases Exemplars would point to a trace that has been thrown away. +Here's more context on the `exemplar="true"` Span attribute: Many users of tracing libraries don't +keep 100% of their trace data, because traces are very repetitive. It is very common to sample only +10% of traces and discard 90%. However, this can be an issue with Exemplars: In 90% of the cases +Exemplars would point to a trace that has been thrown away. -To solve this, the Prometheus Java client library annotates each Span that has been used as an Exemplar with the `exemplar="true"` Span attribute. +To solve this, the Prometheus Java client library annotates each Span that has been used as an +Exemplar with the `exemplar="true"` Span attribute. -The sampling policy in the OpenTelemetry collector can be configured to keep traces with this attribute. There's no risk that this results in a significant increase in trace data, because new Exemplars are only selected every [`minRetentionPeriodSeconds`](../../config/config/#exemplar-properties) seconds. +The sampling policy in the OpenTelemetry collector can be configured to keep traces with this +attribute. There's no risk that this results in a significant increase in trace data, because new +Exemplars are only selected every +[`minRetentionPeriodSeconds`]({{< relref "../config/config.md#exemplar-properties" >}}) seconds. -Here's an example of how to configure OpenTelemetry's [tail sampling processor](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/processor/tailsamplingprocessor/) to sample all Spans marked with `exemplar="true"`, and then discard 90% of the traces: +Here's an example of how to configure OpenTelemetry's +[tail sampling processor](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/processor/tailsamplingprocessor/) +to sample all Spans marked with `exemplar="true"`, and then discard 90% of the traces: ```yaml policies: @@ -38,14 +65,13 @@ policies: { name: keep-exemplars, type: string_attribute, - string_attribute: { key: "exemplar", values: [ "true" ] } - }, - { - name: keep-10-percent, - type: probabilistic, - probabilistic: { sampling_percentage: 10 } + string_attribute: { key: "exemplar", values: ["true"] }, }, + { name: keep-10-percent, type: probabilistic, probabilistic: { sampling_percentage: 10 } }, ] ``` -The [examples/example-exemplar-tail-sampling/](https://github.com/prometheus/client_java/tree/main/examples/example-exemplars-tail-sampling) directory has a complete end-to-end example, with a distributed Java application with two services, an OpenTelemetry collector, Prometheus, Tempo as a trace database, and Grafana dashboards. Use docker-compose as described in the example's README to run the example and explore the results. +The [examples/example-exemplar-tail-sampling/](https://github.com/prometheus/client_java/tree/main/examples/example-exemplars-tail-sampling) +directory has a complete end-to-end example, with a distributed Java application with two services, +an OpenTelemetry collector, Prometheus, Tempo as a trace database, and Grafana dashboards. Use +docker-compose as described in the example's readme to run the example and explore the results. diff --git a/docs/themes/hugo-geekdoc/data/assets.json b/docs/themes/hugo-geekdoc/data/assets.json index 9a34ed54d..81541fbbc 100644 --- a/docs/themes/hugo-geekdoc/data/assets.json +++ b/docs/themes/hugo-geekdoc/data/assets.json @@ -155,4 +155,4 @@ "src": "custom.css", "integrity": "sha512-1kALo+zc1L2u1rvyxPIew+ZDPWhnIA1Ei2rib3eHHbskQW+EMxfI9Ayyva4aV+YRrHvH0zFxvPSFIuZ3mfsbRA==" } -} \ No newline at end of file +} diff --git a/docs/themes/hugo-geekdoc/i18n/nl.yaml b/docs/themes/hugo-geekdoc/i18n/nl.yaml index 8e24d62a4..240bcea5a 100644 --- a/docs/themes/hugo-geekdoc/i18n/nl.yaml +++ b/docs/themes/hugo-geekdoc/i18n/nl.yaml @@ -36,7 +36,7 @@ posts_tagged_with: Alle berichten gemarkeerd met '{{ . }}' footer_build_with: > Gebouwd met Hugo en - + footer_legal_notice: Juridische mededeling footer_privacy_policy: Privacybeleid footer_content_license_prefix: > diff --git a/docs/themes/hugo-geekdoc/layouts/partials/language.html b/docs/themes/hugo-geekdoc/layouts/partials/language.html index fdcafd2b2..8ad972d07 100644 --- a/docs/themes/hugo-geekdoc/layouts/partials/language.html +++ b/docs/themes/hugo-geekdoc/layouts/partials/language.html @@ -1,4 +1,4 @@ -{{ if .Site.IsMultiLingual }} +{{ if .IsTranslated }}