├── .gitattributes ├── .github ├── CODEOWNERS ├── config │ └── markdown-link-check-config.json ├── renovate.json5 ├── repository-settings.md ├── scripts │ ├── markdown-link-check-with-retry.sh │ └── run-oats-tests.sh └── workflows │ ├── build.yml │ ├── codeql-daily.yml │ ├── fossa.yml │ ├── gradle-wrapper-validation.yml │ ├── issue-management-feedback-label.yml │ ├── issue-management-stale-action.yml │ ├── oats-tests.yml │ ├── ossf-scorecard.yml │ ├── reusable-markdown-link-check.yml │ └── reusable-workflow-notification.yml ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── autoconfigure ├── README.md ├── build.gradle.kts └── src │ └── main │ └── java │ └── io │ └── opentelemetry │ └── example │ └── autoconfigure │ └── AutoConfigExample.java ├── build.gradle.kts ├── declarative-configuration ├── README.md ├── build.gradle.kts ├── otel-sdk-config.yaml └── src │ └── main │ └── java │ └── io │ └── opentelemetry │ └── examples │ └── fileconfig │ └── Application.java ├── doc-snippets ├── README.md ├── api │ ├── build.gradle.kts │ └── src │ │ └── main │ │ └── java │ │ └── otel │ │ ├── AsyncCounterUsage.java │ │ ├── AsyncGaugeUsage.java │ │ ├── AsyncUpDownCounterUsage.java │ │ ├── AttributesUsage.java │ │ ├── BaggageUsage.java │ │ ├── ContextUsage.java │ │ ├── CounterUsage.java │ │ ├── ExtractContextUsage.java │ │ ├── GaugeUsage.java │ │ ├── GlobalOpenTelemetryUsage.java │ │ ├── HistogramUsage.java │ │ ├── InjectContextUsage.java │ │ ├── LogRecordUsage.java │ │ ├── NoopUsage.java │ │ ├── OpenTelemetryUsage.java │ │ ├── ProvidersAndScopes.java │ │ ├── SemanticAttributesUsage.java │ │ ├── SpanAndContextUsage.java │ │ ├── SpanUsage.java │ │ ├── UpDownCounterUsage.java │ │ └── Util.java ├── configuration │ ├── build.gradle.kts │ └── src │ │ └── main │ │ └── java │ │ └── otel │ │ ├── AutoConfiguredSdk.java │ │ ├── ContextPropagatorsConfig.java │ │ ├── CustomLogRecordExporter.java │ │ ├── CustomLogRecordExporterProvider.java │ │ ├── CustomLogRecordProcessor.java │ │ ├── CustomMetricExporter.java │ │ ├── CustomMetricExporterProvider.java │ │ ├── CustomMetricReader.java │ │ ├── CustomResourceProvider.java │ │ ├── CustomSampler.java │ │ ├── CustomSamplerProvider.java │ │ ├── CustomSpanExporter.java │ │ ├── CustomSpanExporterProvider.java │ │ ├── CustomSpanProcessor.java │ │ ├── CustomTextMapPropagator.java │ │ ├── CustomTextMapPropagatorProvider.java │ │ ├── CustomizedAutoConfiguredSdk.java │ │ ├── CustomizerProvider.java │ │ ├── LogLimitsConfig.java │ │ ├── LogRecordExporterConfig.java │ │ ├── LogRecordProcessorConfig.java │ │ ├── MetricExporterConfig.java │ │ ├── MetricReaderConfig.java │ │ ├── OpenTelemetrySdkConfig.java │ │ ├── OtlpAuthenticationConfig.java │ │ ├── ResourceConfig.java │ │ ├── SamplerConfig.java │ │ ├── SdkLoggerProviderConfig.java │ │ ├── SdkMeterProviderConfig.java │ │ ├── SdkTracerProviderConfig.java │ │ ├── SpanExporterConfig.java │ │ ├── SpanLimitsConfig.java │ │ ├── SpanProcessorConfig.java │ │ └── ViewConfig.java ├── exporters │ ├── build.gradle.kts │ └── src │ │ └── main │ │ └── java │ │ └── otel │ │ ├── BatchExporter.java │ │ ├── DiceApplication.java │ │ ├── PrometheusExporter.java │ │ ├── SimpleExporter.java │ │ └── ZipkinExporter.java ├── getting-started │ ├── build.gradle.kts │ └── src │ │ └── main │ │ └── java │ │ └── otel │ │ ├── DiceApplication.java │ │ └── RollController.java └── spring-starter │ ├── build.gradle.kts │ └── src │ └── main │ └── java │ └── otel │ ├── Application.java │ ├── CustomAuth.java │ ├── FilterPaths.java │ ├── RestClientConfig.java │ ├── RestClientController.java │ ├── RestTemplateConfig.java │ ├── RestTemplateController.java │ ├── TracedClass.java │ ├── WebClientConfig.java │ └── WebClientController.java ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── grpc ├── README.md ├── build.gradle.kts ├── client_trace.png ├── server_trace.png ├── src │ └── main │ │ ├── java │ │ └── io │ │ │ └── opentelemetry │ │ │ └── examples │ │ │ └── grpc │ │ │ ├── ExampleConfiguration.java │ │ │ ├── HelloWorldClient.java │ │ │ └── HelloWorldServer.java │ │ └── proto │ │ └── helloworld.proto └── trace_result.png ├── http ├── README.md ├── build.gradle.kts └── src │ └── main │ └── java │ └── io │ └── opentelemetry │ └── example │ └── http │ ├── ExampleConfiguration.java │ ├── HttpClient.java │ └── HttpServer.java ├── jaeger ├── README.md ├── build.gradle.kts └── src │ └── main │ └── java │ └── io │ └── opentelemetry │ └── example │ └── jaeger │ ├── ExampleConfiguration.java │ └── JaegerExample.java ├── javaagent ├── Dockerfile ├── README.md ├── build.gradle.kts ├── collector-config.yaml ├── docker-compose.yml ├── sdk-config.yaml └── src │ └── main │ └── java │ └── io │ └── opentelemetry │ └── example │ └── javagent │ ├── Application.java │ └── Controller.java ├── kotlin-extension ├── README.md ├── build.gradle.kts └── src │ └── main │ └── kotlin │ └── io │ └── opentelemetry │ └── example │ └── kotlinextension │ ├── Application.kt │ └── CoroutineContextExample.kt ├── log-appender ├── README.md ├── build.gradle.kts ├── docker-compose.yml ├── otel-config.yaml └── src │ └── main │ ├── java │ └── io │ │ └── opentelemetry │ │ └── example │ │ └── logappender │ │ └── Application.java │ └── resources │ ├── log4j2.xml │ └── logback.xml ├── logging-k8s-stdout-otlp-json ├── Dockerfile ├── README.md ├── build.gradle.kts ├── generate-traffic.sh ├── k3d.sh ├── k8s │ ├── collector-configmap.yaml │ ├── dice.yaml │ └── lgtm.yaml ├── oats.yaml ├── otel-collector-otlpjson-pipeline.png ├── otlpjson-architecture.png └── src │ └── main │ ├── java │ └── io │ │ └── opentelemetry │ │ └── example │ │ ├── RollController.java │ │ └── SpringBootApp.java │ └── resources │ └── logback-spring.xml ├── logging ├── build.gradle.kts └── src │ └── main │ └── java │ └── io │ └── opentelemetry │ └── example │ └── logging │ ├── ExampleConfiguration.java │ └── LoggingExporterExample.java ├── manual-tracing ├── build.gradle.kts └── src │ └── main │ └── java │ └── io │ └── opentelemetry │ └── example │ └── tracing │ ├── ExampleConfiguration.java │ └── ManualTracingExample.java ├── metrics ├── build.gradle.kts └── src │ └── main │ └── java │ └── io │ └── opentelemetry │ └── example │ └── metrics │ ├── DoubleCounterExample.java │ ├── ExponentialHistogramExample.java │ ├── GaugeExample.java │ ├── HistogramExample.java │ ├── LongCounterExample.java │ └── ViewExample.java ├── micrometer-shim ├── README.md ├── build.gradle.kts └── src │ └── main │ └── java │ └── io │ └── opentelemetry │ └── example │ └── micrometer │ ├── Application.java │ ├── Controller.java │ └── Service.java ├── otlp ├── README.md ├── build.gradle.kts ├── docker │ ├── .env │ ├── README.md │ ├── docker-compose.yaml │ ├── otel-collector-config-demo.yaml │ └── prometheus.yaml └── src │ └── main │ └── java │ └── io │ └── opentelemetry │ └── example │ └── otlp │ ├── ExampleConfiguration.java │ └── OtlpExporterExample.java ├── prometheus ├── Dockerfile ├── README.md ├── build.gradle.kts ├── docker-compose.yml ├── prometheus.yml └── src │ └── main │ └── java │ └── io │ └── opentelemetry │ └── example │ └── prometheus │ ├── ExampleConfiguration.java │ └── PrometheusExample.java ├── resource-detection-gcp ├── README.md ├── build.gradle.kts ├── k8s │ └── job.yaml └── src │ └── main │ └── java │ └── io │ └── opentelemetry │ └── resource │ └── gcp │ └── GCPResourceExample.java ├── sdk-usage ├── README.md ├── build.gradle.kts └── src │ └── main │ └── java │ └── io │ └── opentelemetry │ └── sdk │ └── example │ ├── ConfigureSpanProcessorExample.java │ └── ConfigureTraceExample.java ├── settings.gradle.kts ├── spring-native ├── README.md ├── build.gradle.kts ├── collector-spring-native-config.yaml ├── docker-compose.yml └── src │ └── main │ ├── java │ └── io │ │ └── opentelemetry │ │ └── example │ │ └── graal │ │ ├── Application.java │ │ ├── Controller.java │ │ ├── OpenTelemetryConfig.java │ │ └── SqlExecutor.java │ └── resources │ └── application.properties ├── telemetry-testing ├── README.md ├── build.gradle.kts └── src │ ├── main │ └── java │ │ └── io │ │ └── opentelemetry │ │ └── example │ │ └── telemetry │ │ ├── Application.java │ │ └── Controller.java │ └── test │ └── java │ └── io │ └── opentelemetry │ └── example │ └── telemetry │ └── ApplicationTest.java └── zipkin ├── README.md ├── build.gradle.kts └── src └── main └── java └── io └── opentelemetry └── example └── zipkin ├── ExampleConfiguration.java └── ZipkinExample.java /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | 3 | *.bat text eol=crlf 4 | *.cmd text eol=crlf 5 | 6 | *.jar -text 7 | *.png -text 8 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | ##################################################### 2 | # 3 | # List of approvers and maintainers 4 | # 5 | ##################################################### 6 | # 7 | # Learn about membership in OpenTelemetry community: 8 | # https://github.com/open-telemetry/community/blob/master/community-membership.md 9 | # 10 | # 11 | # Learn about CODEOWNERS file format: 12 | # https://help.github.com/en/articles/about-code-owners 13 | # 14 | 15 | * @open-telemetry/java-approvers @open-telemetry/java-instrumentation-approvers 16 | -------------------------------------------------------------------------------- /.github/config/markdown-link-check-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "retryOn429" : true, 3 | "ignorePatterns" : [ 4 | { 5 | "pattern" : "^http://localhost:.*" 6 | }, 7 | { 8 | "pattern" : "^http://0\\.0\\.0\\.0:.*" 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /.github/renovate.json5: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:best-practices", 5 | "helpers:pinGitHubActionDigestsToSemver", 6 | "customManagers:dockerfileVersions" // used by logging-k8s-stdout-otlp-json/Dockerfile 7 | ], 8 | "packageRules": [ 9 | { 10 | "matchPackageNames": [ 11 | "io.opentelemetry:**", 12 | "io.opentelemetry.instrumentation:**", 13 | "io.opentelemetry.contrib:**", 14 | "io.opentelemetry.semconv:**", 15 | "io.opentelemetry.proto:**" 16 | ], 17 | // Renovate's default behavior is only to update from unstable -> unstable if it's for the 18 | // major.minor.patch, under the assumption that you would want to update to the stable version 19 | // of that release instead of the unstable version for a future release 20 | "ignoreUnstable": false 21 | }, 22 | { 23 | groupName: 'opentelemetry instrumentation packages', 24 | matchPackageNames: [ 25 | 'io.opentelemetry.instrumentation:**', 26 | 'io.opentelemetry.javaagent:**', 27 | 'open-telemetry/opentelemetry-java-instrumentation' // for logging-k8s-stdout-otlp-json/Dockerfile 28 | ], 29 | }, 30 | { 31 | // intentionally using Java 11 in some examples 32 | // not using matchUpdateTypes "major", because renovate wants to bump "11-jre" to "11.0.19_7-jre" 33 | "matchPackageNames": ["eclipse-temurin"], 34 | "enabled": false 35 | }, 36 | { 37 | // Skip locally built dice image used in logging-k8s-stdout-otlp-json 38 | "matchManagers": ["kubernetes"], 39 | "matchDatasources": ["docker"], 40 | "matchPackageNames": ["dice"], 41 | "enabled": false 42 | } 43 | ], 44 | "kubernetes": { 45 | "managerFilePatterns": ["/^logging-k8s-stdout-otlp-json/k8s/.+\\.yaml$/"] 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /.github/repository-settings.md: -------------------------------------------------------------------------------- 1 | # Repository settings 2 | 3 | Same as [opentelemetry-java-instrumentation repository settings](https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/.github/repository-settings.md#repository-settings), 4 | except that the branch protection rules for `release/*`, `gh-pages`, and `opentelemetrybot/*` are not needed in this repository. 5 | -------------------------------------------------------------------------------- /.github/scripts/markdown-link-check-with-retry.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | # this script helps to reduce sporadic link check failures by retrying at a file-by-file level 4 | 5 | retry_count=3 6 | 7 | for file in "$@"; do 8 | for i in $(seq 1 $retry_count); do 9 | if markdown-link-check --config "$(dirname "$0")/../config/markdown-link-check-config.json" \ 10 | "$file"; then 11 | break 12 | elif [[ $i -eq $retry_count ]]; then 13 | exit 1 14 | fi 15 | sleep 5 16 | done 17 | done 18 | -------------------------------------------------------------------------------- /.github/scripts/run-oats-tests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euo pipefail 4 | 5 | pushd logging-k8s-stdout-otlp-json 6 | ../gradlew assemble 7 | popd 8 | 9 | wget -q -O - https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | bash 10 | 11 | go install github.com/grafana/oats@v0.3.1 12 | oats -timeout 5m logging-k8s-stdout-otlp-json/ 13 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | workflow_dispatch: 9 | 10 | concurrency: 11 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} 12 | cancel-in-progress: true 13 | 14 | jobs: 15 | build: 16 | runs-on: ${{ matrix.os }} 17 | strategy: 18 | matrix: 19 | os: 20 | - macos-latest 21 | - ubuntu-latest 22 | - windows-latest 23 | steps: 24 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 25 | 26 | - name: Set up JDK for running Gradle 27 | uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 28 | with: 29 | distribution: temurin 30 | java-version: 17 31 | 32 | - name: Set up gradle 33 | uses: gradle/actions/setup-gradle@8379f6a1328ee0e06e2bb424dadb7b159856a326 # v4.4.0 34 | with: 35 | cache-read-only: ${{ github.event_name == 'pull_request' }} 36 | 37 | - name: Build 38 | run: ./gradlew clean check shadowJar 39 | 40 | - run: java -cp sdk-usage/build/libs/opentelemetry-examples-sdk-usage-0.1.0-SNAPSHOT-all.jar io.opentelemetry.sdk.example.ConfigureSpanProcessorExample 41 | 42 | # this is not a required check to avoid blocking pull requests if external links break 43 | markdown-link-check: 44 | uses: ./.github/workflows/reusable-markdown-link-check.yml 45 | 46 | required-status-check: 47 | needs: 48 | - build 49 | runs-on: ubuntu-latest 50 | if: always() 51 | steps: 52 | - if: needs.build.result != 'success' 53 | run: exit 1 54 | -------------------------------------------------------------------------------- /.github/workflows/codeql-daily.yml: -------------------------------------------------------------------------------- 1 | name: CodeQL (daily) 2 | 3 | on: 4 | schedule: 5 | # Daily at 01:30 (UTC) 6 | - cron: '30 1 * * *' 7 | workflow_dispatch: 8 | 9 | jobs: 10 | analyze: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 15 | 16 | - name: Set up Java 17 17 | uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 18 | with: 19 | distribution: temurin 20 | java-version: 17 21 | 22 | - name: Initialize CodeQL 23 | uses: github/codeql-action/init@fca7ace96b7d713c7035871441bd52efbe39e27e # v3.28.19 24 | with: 25 | languages: java 26 | # using "latest" helps to keep up with the latest Kotlin support 27 | # see https://github.com/github/codeql-action/issues/1555#issuecomment-1452228433 28 | tools: latest 29 | 30 | - name: Set up gradle 31 | uses: gradle/actions/setup-gradle@8379f6a1328ee0e06e2bb424dadb7b159856a326 # v4.4.0 32 | - name: Assemble 33 | # skipping build cache is needed so that all modules will be analyzed 34 | run: ./gradlew assemble --no-build-cache 35 | 36 | - name: Perform CodeQL analysis 37 | uses: github/codeql-action/analyze@fca7ace96b7d713c7035871441bd52efbe39e27e # v3.28.19 38 | 39 | workflow-notification: 40 | needs: 41 | - analyze 42 | if: always() 43 | uses: ./.github/workflows/reusable-workflow-notification.yml 44 | with: 45 | success: ${{ needs.analyze.result == 'success' }} 46 | -------------------------------------------------------------------------------- /.github/workflows/fossa.yml: -------------------------------------------------------------------------------- 1 | name: FOSSA scanning 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | permissions: 9 | contents: read 10 | 11 | jobs: 12 | fossa: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 16 | 17 | - uses: fossas/fossa-action@3ebcea1862c6ffbd5cf1b4d0bd6b3fe7bd6f2cac # v1.7.0 18 | with: 19 | api-key: ${{secrets.FOSSA_API_KEY}} 20 | team: OpenTelemetry 21 | -------------------------------------------------------------------------------- /.github/workflows/gradle-wrapper-validation.yml: -------------------------------------------------------------------------------- 1 | name: Gradle wrapper validation 2 | 3 | on: 4 | push: 5 | pull_request: 6 | 7 | permissions: 8 | contents: read 9 | 10 | jobs: 11 | gradle-wrapper-validation: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 15 | 16 | # this needs to be in its own workflow in order to make OSSF scorecard happy 17 | - uses: gradle/actions/wrapper-validation@8379f6a1328ee0e06e2bb424dadb7b159856a326 # v4.4.0 18 | -------------------------------------------------------------------------------- /.github/workflows/issue-management-feedback-label.yml: -------------------------------------------------------------------------------- 1 | name: Issue management - remove needs feedback label 2 | 3 | on: 4 | issue_comment: 5 | types: [created] 6 | 7 | jobs: 8 | issue_comment: 9 | if: > 10 | contains(github.event.issue.labels.*.name, 'needs author feedback') && 11 | github.event.comment.user.login == github.event.issue.user.login 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 15 | 16 | - name: Remove label 17 | env: 18 | ISSUE_NUMBER: ${{ github.event.issue.number }} 19 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 20 | run: | 21 | gh issue edit --remove-label "needs author feedback" $ISSUE_NUMBER 22 | -------------------------------------------------------------------------------- /.github/workflows/issue-management-stale-action.yml: -------------------------------------------------------------------------------- 1 | name: Issue management - run stale action 2 | 3 | on: 4 | schedule: 5 | # hourly at minute 23 6 | - cron: "23 * * * *" 7 | 8 | permissions: 9 | contents: read 10 | 11 | jobs: 12 | stale: 13 | permissions: 14 | issues: write # for actions/stale to close stale issues 15 | pull-requests: write # for actions/stale to close stale PRs 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 # v9.1.0 19 | with: 20 | repo-token: ${{ secrets.GITHUB_TOKEN }} 21 | days-before-stale: 7 22 | days-before-close: 7 23 | only-labels: "needs author feedback" 24 | stale-issue-message: > 25 | This has been automatically marked as stale because it has been marked 26 | as needing author feedback and has not had any activity for 7 days. 27 | It will be closed if no further activity occurs within 7 days of this comment. 28 | stale-pr-message: > 29 | This has been automatically marked as stale because it has been marked 30 | as needing author feedback and has not had any activity for 7 days. 31 | It will be closed if no further activity occurs within 7 days of this comment. 32 | -------------------------------------------------------------------------------- /.github/workflows/oats-tests.yml: -------------------------------------------------------------------------------- 1 | name: OATS Tests 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | paths: 8 | - .github/workflows/oats-tests.yml 9 | - 'logging-k8s-stdout-otlp-json/**' 10 | workflow_dispatch: 11 | 12 | jobs: 13 | acceptance-tests: 14 | runs-on: ubuntu-24.04 15 | steps: 16 | - name: Check out 17 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 18 | 19 | - name: Set up JDK for running Gradle 20 | uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 21 | with: 22 | distribution: temurin 23 | java-version: 17 24 | 25 | - name: Set up gradle 26 | uses: gradle/actions/setup-gradle@8379f6a1328ee0e06e2bb424dadb7b159856a326 # v4.4.0 27 | with: 28 | cache-read-only: ${{ github.event_name == 'pull_request' }} 29 | 30 | - name: Set up Go 31 | uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 32 | with: 33 | go-version: '1.24' 34 | 35 | - name: Run acceptance tests 36 | run: .github/scripts/run-oats-tests.sh 37 | -------------------------------------------------------------------------------- /.github/workflows/ossf-scorecard.yml: -------------------------------------------------------------------------------- 1 | name: OSSF Scorecard 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | schedule: 8 | - cron: "2 15 * * 1" # once a week 9 | workflow_dispatch: 10 | 11 | permissions: read-all 12 | 13 | jobs: 14 | analysis: 15 | runs-on: ubuntu-latest 16 | permissions: 17 | # Needed for Code scanning upload 18 | security-events: write 19 | # Needed for GitHub OIDC token if publish_results is true 20 | id-token: write 21 | steps: 22 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 23 | with: 24 | persist-credentials: false 25 | 26 | - uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2 27 | with: 28 | results_file: results.sarif 29 | results_format: sarif 30 | publish_results: true 31 | 32 | # Upload the results as artifacts (optional). Commenting out will disable 33 | # uploads of run results in SARIF format to the repository Actions tab. 34 | # https://docs.github.com/en/actions/advanced-guides/storing-workflow-data-as-artifacts 35 | - name: "Upload artifact" 36 | uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 37 | with: 38 | name: SARIF file 39 | path: results.sarif 40 | retention-days: 5 41 | 42 | # Upload the results to GitHub's code scanning dashboard (optional). 43 | # Commenting out will disable upload of results to your repo's Code Scanning dashboard 44 | - name: "Upload to code-scanning" 45 | uses: github/codeql-action/upload-sarif@fca7ace96b7d713c7035871441bd52efbe39e27e # v3.28.19 46 | with: 47 | sarif_file: results.sarif 48 | -------------------------------------------------------------------------------- /.github/workflows/reusable-markdown-link-check.yml: -------------------------------------------------------------------------------- 1 | name: Reusable - Markdown link check 2 | 3 | on: 4 | workflow_call: 5 | 6 | permissions: 7 | contents: read 8 | 9 | jobs: 10 | markdown-link-check: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 14 | 15 | - name: Install markdown-link-check 16 | # TODO(jack-berg): use latest when config file reading bug is fixed: https://github.com/tcort/markdown-link-check/issues/246 17 | run: npm install -g markdown-link-check@3.10.3 18 | 19 | - name: Run markdown-link-check 20 | run: | 21 | find . -type f \ 22 | -name '*.md' \ 23 | | xargs .github/scripts/markdown-link-check-with-retry.sh 24 | -------------------------------------------------------------------------------- /.github/workflows/reusable-workflow-notification.yml: -------------------------------------------------------------------------------- 1 | # this is useful because notifications for scheduled workflows are only sent to the user who 2 | # initially created the given workflow 3 | name: Reusable - Workflow notification 4 | 5 | on: 6 | workflow_call: 7 | inputs: 8 | success: 9 | type: boolean 10 | required: true 11 | 12 | jobs: 13 | workflow-notification: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 17 | 18 | - name: Open issue or add comment if issue already open 19 | env: 20 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 21 | run: | 22 | number=$(gh issue list --search "Workflow failed: $GITHUB_WORKFLOW" --limit 1 --json number -q .[].number) 23 | 24 | echo $number 25 | echo ${{ inputs.success }} 26 | 27 | if [[ $number ]]; then 28 | if [[ "${{ inputs.success }}" == "true" ]]; then 29 | gh issue close $number 30 | else 31 | gh issue comment $number \ 32 | --body "See [$GITHUB_WORKFLOW #$GITHUB_RUN_NUMBER](https://github.com/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID)." 33 | fi 34 | elif [[ "${{ inputs.success }}" == "false" ]]; then 35 | gh issue create --title "Workflow failed: $GITHUB_WORKFLOW (#$GITHUB_RUN_NUMBER)" \ 36 | --body "See [$GITHUB_WORKFLOW #$GITHUB_RUN_NUMBER](https://github.com/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID)." 37 | fi 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Gradle 2 | build 3 | .gradle 4 | local.properties 5 | out/ 6 | 7 | # Maven (proto) 8 | target 9 | 10 | # IntelliJ IDEA 11 | .idea 12 | *.iml 13 | 14 | # Eclipse 15 | .classpath 16 | .project 17 | .settings 18 | bin 19 | 20 | # NetBeans 21 | /.nb-gradle 22 | /.nb-gradle-properties 23 | 24 | # VS Code 25 | .vscode 26 | 27 | # OS X 28 | .DS_Store 29 | 30 | # Emacs 31 | *~ 32 | \#*\# 33 | 34 | # Vim 35 | .swp 36 | 37 | # Polyglot runtime manager (asdf rust clone) 38 | .rtx.toml -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Welcome to the OpenTelemetry Java Examples repository! 4 | 5 | ## Building 6 | 7 | Java 17 or higher is required to build the projects in this repository. 8 | To check your Java version, run: 9 | 10 | ```bash 11 | java -version 12 | ``` 13 | 14 | To build the project, run: 15 | 16 | ```bash 17 | ./gradlew assemble 18 | ``` 19 | 20 | ## Style guide 21 | 22 | This repository follows the OpenTelemetry Java 23 | repository's [style guide](https://github.com/open-telemetry/opentelemetry-java/blob/main/CONTRIBUTING.md#style-guideline). 24 | 25 | ## Gradle conventions 26 | 27 | - Use kotlin instead of groovy 28 | - Plugin versions should be specified in `settings.gradle.kts`, not in individual modules 29 | - All modules use `plugins { id("otel.java-conventions") }` 30 | -------------------------------------------------------------------------------- /autoconfigure/README.md: -------------------------------------------------------------------------------- 1 | # SDK autoconfiguration example 2 | 3 | This is a simple example that demonstrates the usage of 4 | the [OpenTelemetry SDK Autoconfigure](https://github.com/open-telemetry/opentelemetry-java/tree/main/sdk-extensions/autoconfigure) 5 | module. 6 | 7 | ## Prerequisites 8 | 9 | * Java 1.8 10 | 11 | ## How to run 12 | 13 | First build this example application: 14 | 15 | ```shell 16 | ../gradlew shadowJar 17 | ``` 18 | 19 | Then start the example application with the logging exporter configured: 20 | 21 | ```shell 22 | java -Dotel.traces.exporter=console \ 23 | -Dotel.metrics.exporter=console \ 24 | -Dotel.logs.exporter=console \ 25 | -cp build/libs/opentelemetry-examples-autoconfigure-0.1.0-SNAPSHOT-all.jar \ 26 | io.opentelemetry.example.autoconfigure.AutoConfigExample 27 | ``` 28 | 29 | Alternatively, instead of system properties you can use environment variables: 30 | 31 | ```shell 32 | export OTEL_TRACES_EXPORTER=console 33 | export OTEL_METRICS_EXPORTER=console 34 | export OTEL_LOGS_EXPORTER=console 35 | 36 | java -cp build/libs/opentelemetry-examples-autoconfigure-0.1.0-SNAPSHOT-all.jar \ 37 | io.opentelemetry.example.autoconfigure.AutoConfigExample 38 | ``` 39 | 40 | Full documentation of all supported properties can be found in 41 | the [OpenTelemetry SDK Autoconfigure README](https://github.com/open-telemetry/opentelemetry-java/tree/main/sdk-extensions/autoconfigure). 42 | 43 | After running the app you should see the trace printed out in the console: 44 | 45 | ``` 46 | ... 47 | INFO: 'important work' : ca3938a5793f6f9aba5c757f536a50cb b5e826c981112198 INTERNAL [tracer: io.opentelemetry.example.autoconfigure.AutoConfigExample:] AttributesMap{data={foo=42, bar=a string!}, capacity=128, totalAddedValues=2} 48 | ... 49 | ``` 50 | 51 | Congratulations! You are now collecting traces using OpenTelemetry. 52 | -------------------------------------------------------------------------------- /autoconfigure/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("java") 3 | } 4 | 5 | description = "OpenTelemetry Examples for SDK autoconfiguration" 6 | val moduleName by extra { "io.opentelemetry.examples.autoconfigure" } 7 | 8 | java { 9 | toolchain { 10 | languageVersion.set(JavaLanguageVersion.of(8)) 11 | } 12 | } 13 | 14 | dependencies { 15 | implementation("io.opentelemetry:opentelemetry-api") 16 | implementation("io.opentelemetry:opentelemetry-exporter-logging") 17 | implementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure") 18 | } 19 | -------------------------------------------------------------------------------- /autoconfigure/src/main/java/io/opentelemetry/example/autoconfigure/AutoConfigExample.java: -------------------------------------------------------------------------------- 1 | package io.opentelemetry.example.autoconfigure; 2 | 3 | import io.opentelemetry.api.OpenTelemetry; 4 | import io.opentelemetry.api.trace.Span; 5 | import io.opentelemetry.api.trace.Tracer; 6 | import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; 7 | 8 | /** 9 | * An example of using {@link io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk} and 10 | * logging exporter: {@link io.opentelemetry.exporter.logging.LoggingSpanExporter}. 11 | */ 12 | public final class AutoConfigExample { 13 | private static final String INSTRUMENTATION_NAME = AutoConfigExample.class.getName(); 14 | 15 | public static void main(String[] args) throws InterruptedException { 16 | // Let the SDK configure itself using environment variables and system properties 17 | OpenTelemetry openTelemetry = AutoConfiguredOpenTelemetrySdk.initialize().getOpenTelemetrySdk(); 18 | 19 | AutoConfigExample example = new AutoConfigExample(openTelemetry); 20 | // Do some real work that'll emit telemetry 21 | example.doWork(); 22 | } 23 | 24 | private final Tracer tracer; 25 | 26 | public AutoConfigExample(OpenTelemetry openTelemetry) { 27 | this.tracer = openTelemetry.getTracer(INSTRUMENTATION_NAME); 28 | } 29 | 30 | public void doWork() throws InterruptedException { 31 | Span span = 32 | tracer 33 | .spanBuilder("important work") 34 | .setAttribute("foo", 42) 35 | .setAttribute("bar", "a string!") 36 | .startSpan(); 37 | try { 38 | Thread.sleep(1000); 39 | } finally { 40 | span.end(); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("com.diffplug.spotless") 3 | id("com.github.johnrengelman.shadow") apply false 4 | id("java-library") 5 | } 6 | 7 | subprojects { 8 | apply(plugin = "com.diffplug.spotless") 9 | apply(plugin = "java-library") 10 | apply(plugin = "com.github.johnrengelman.shadow") 11 | 12 | group = "io.opentelemetry" 13 | version = "0.1.0-SNAPSHOT" 14 | 15 | repositories { 16 | mavenCentral() 17 | } 18 | 19 | dependencies { 20 | // using the bom ensures that all of your opentelemetry dependency versions are aligned 21 | implementation(platform("io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom-alpha:2.16.0-alpha")) 22 | } 23 | 24 | spotless { 25 | java { 26 | targetExclude("**/generated/**") 27 | googleJavaFormat() 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /declarative-configuration/README.md: -------------------------------------------------------------------------------- 1 | # Declarative Configuration Example 2 | 3 | This example demonstrates how to use [declarative configuration](https://opentelemetry.io/docs/specs/otel/configuration/#declarative-configuration) to configure the OpenTelemetry SDK using a YAML configuration file as defined in [opentelemetry-configuration](https://github.com/open-telemetry/opentelemetry-configuration). 4 | 5 | The configuration file is located at [otel-sdk-config.yaml](./otel-sdk-config.yaml). 6 | 7 | # How to run 8 | 9 | ## Prerequisites 10 | 11 | * Java 1.8 12 | 13 | ## Run 14 | 15 | ```shell script 16 | export OTEL_EXPERIMENTAL_CONFIG_FILE=$(pwd)/otel-sdk-config.yaml 17 | ../gradlew run 18 | ``` 19 | 20 | Observe how data is printed to the console as configured in [otel-sdk-config.yaml](./otel-sdk-config.yaml). 21 | 22 | For use with the OpenTelemetry Java, see [Java Agent declarative configuration](../javaagent/README.md#declarative-configuration). 23 | -------------------------------------------------------------------------------- /declarative-configuration/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("java") 3 | id("application") 4 | } 5 | 6 | description = "OpenTelemetry Example for Declarative Configuration" 7 | val moduleName by extra { "io.opentelemetry.examples.fileconfig" } 8 | 9 | dependencies { 10 | implementation("io.opentelemetry:opentelemetry-api") 11 | implementation("io.opentelemetry:opentelemetry-sdk") 12 | implementation("io.opentelemetry:opentelemetry-exporter-logging") 13 | implementation("io.opentelemetry:opentelemetry-sdk-extension-incubator") 14 | } 15 | 16 | application { 17 | mainClass = "io.opentelemetry.examples.fileconfig.Application" 18 | } 19 | -------------------------------------------------------------------------------- /declarative-configuration/otel-sdk-config.yaml: -------------------------------------------------------------------------------- 1 | # See https://github.com/open-telemetry/opentelemetry-configuration for details on schema and examples 2 | 3 | file_format: "0.3" 4 | 5 | resource: 6 | attributes: 7 | - name: service.name 8 | value: file-configuration-example 9 | 10 | tracer_provider: 11 | processors: 12 | - batch: 13 | exporter: 14 | console: 15 | 16 | meter_provider: 17 | readers: 18 | - periodic: 19 | exporter: 20 | console: 21 | views: 22 | - selector: 23 | instrument_type: histogram 24 | stream: 25 | aggregation: 26 | drop: 27 | 28 | propagator: 29 | composite: 30 | - tracecontext 31 | - baggage 32 | -------------------------------------------------------------------------------- /doc-snippets/README.md: -------------------------------------------------------------------------------- 1 | The projects in this directory contain code snippets that are used in the OpenTelemetry 2 | documentation in https://opentelemetry.io/docs/languages/java/ and 3 | https://opentelemetry.io/docs/zero-code/java/. 4 | -------------------------------------------------------------------------------- /doc-snippets/api/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("java") 3 | } 4 | 5 | val moduleName by extra { "io.opentelemetry.examples.docs.configuration" } 6 | 7 | dependencies { 8 | implementation("io.opentelemetry:opentelemetry-api") 9 | 10 | implementation("io.opentelemetry.semconv:opentelemetry-semconv") 11 | implementation("io.opentelemetry.semconv:opentelemetry-semconv-incubating:1.32.0-alpha") 12 | } 13 | -------------------------------------------------------------------------------- /doc-snippets/api/src/main/java/otel/AsyncCounterUsage.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import static otel.Util.WIDGET_COLOR; 4 | import static otel.Util.WIDGET_SHAPE; 5 | import static otel.Util.computeWidgetColor; 6 | import static otel.Util.computeWidgetShape; 7 | 8 | import io.opentelemetry.api.common.Attributes; 9 | import io.opentelemetry.api.metrics.Meter; 10 | import io.opentelemetry.api.metrics.ObservableLongCounter; 11 | import java.util.concurrent.atomic.AtomicLong; 12 | 13 | public class AsyncCounterUsage { 14 | // Pre-allocate attributes whenever possible 15 | private static final Attributes WIDGET_RED_CIRCLE = Util.WIDGET_RED_CIRCLE; 16 | 17 | public static void asyncCounterUsage(Meter meter) { 18 | AtomicLong widgetCount = new AtomicLong(); 19 | 20 | // Construct an async counter to observe an existing counter in a callback 21 | ObservableLongCounter asyncCounter = 22 | meter 23 | .counterBuilder("fully.qualified.counter") 24 | .setDescription("A count of produced widgets") 25 | .setUnit("{widget}") 26 | // Uncomment to optionally change the type to double 27 | // .ofDoubles() 28 | .buildWithCallback( 29 | // the callback is invoked when a MetricReader reads metrics 30 | observableMeasurement -> { 31 | long currentWidgetCount = widgetCount.get(); 32 | 33 | // Record a measurement with no attributes. 34 | // Attributes defaults to Attributes.empty(). 35 | observableMeasurement.record(currentWidgetCount); 36 | 37 | // Record a measurement with attributes, using pre-allocated attributes whenever 38 | // possible. 39 | observableMeasurement.record(currentWidgetCount, WIDGET_RED_CIRCLE); 40 | // Sometimes, attributes must be computed using application context. 41 | observableMeasurement.record( 42 | currentWidgetCount, 43 | Attributes.of( 44 | WIDGET_SHAPE, computeWidgetShape(), WIDGET_COLOR, computeWidgetColor())); 45 | }); 46 | 47 | // Optionally close the counter to unregister the callback when required 48 | asyncCounter.close(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /doc-snippets/api/src/main/java/otel/AsyncGaugeUsage.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import static otel.Util.WIDGET_COLOR; 4 | import static otel.Util.WIDGET_SHAPE; 5 | import static otel.Util.computeWidgetColor; 6 | import static otel.Util.computeWidgetShape; 7 | 8 | import io.opentelemetry.api.common.Attributes; 9 | import io.opentelemetry.api.metrics.Meter; 10 | import io.opentelemetry.api.metrics.ObservableDoubleGauge; 11 | import java.util.concurrent.atomic.AtomicReference; 12 | 13 | public class AsyncGaugeUsage { 14 | private static final Attributes WIDGET_RED_CIRCLE = Util.WIDGET_RED_CIRCLE; 15 | 16 | public static void asyncGaugeUsage(Meter meter) { 17 | AtomicReference processingLineTemp = new AtomicReference<>(273.0); 18 | 19 | // Construct an async counter to observe an existing counter in a callback 20 | ObservableDoubleGauge asyncGauge = 21 | meter 22 | .gaugeBuilder("fully.qualified.gauge") 23 | .setDescription("The current temperature of the widget processing line") 24 | .setUnit("K") 25 | // Uncomment to optionally change the type to long 26 | // .ofLongs() 27 | .buildWithCallback( 28 | // the callback is invoked when a MetricReader reads metrics 29 | observableMeasurement -> { 30 | double currentWidgetCount = processingLineTemp.get(); 31 | 32 | // Record a measurement with no attributes. 33 | // Attributes defaults to Attributes.empty(). 34 | observableMeasurement.record(currentWidgetCount); 35 | 36 | // Record a measurement with attributes, using pre-allocated attributes whenever 37 | // possible. 38 | observableMeasurement.record(currentWidgetCount, WIDGET_RED_CIRCLE); 39 | // Sometimes, attributes must be computed using application context. 40 | observableMeasurement.record( 41 | currentWidgetCount, 42 | Attributes.of( 43 | WIDGET_SHAPE, computeWidgetShape(), WIDGET_COLOR, computeWidgetColor())); 44 | }); 45 | 46 | // Optionally close the gauge to unregister the callback when required 47 | asyncGauge.close(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /doc-snippets/api/src/main/java/otel/AsyncUpDownCounterUsage.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import static otel.Util.WIDGET_COLOR; 4 | import static otel.Util.WIDGET_SHAPE; 5 | import static otel.Util.computeWidgetColor; 6 | import static otel.Util.computeWidgetShape; 7 | 8 | import io.opentelemetry.api.common.Attributes; 9 | import io.opentelemetry.api.metrics.Meter; 10 | import io.opentelemetry.api.metrics.ObservableLongUpDownCounter; 11 | import java.util.concurrent.atomic.AtomicLong; 12 | 13 | public class AsyncUpDownCounterUsage { 14 | private static final Attributes WIDGET_RED_CIRCLE = Util.WIDGET_RED_CIRCLE; 15 | 16 | public static void asyncUpDownCounterUsage(Meter meter) { 17 | AtomicLong queueLength = new AtomicLong(); 18 | 19 | // Construct an async updowncounter to observe an existing up down counter in a callback 20 | ObservableLongUpDownCounter asyncUpDownCounter = 21 | meter 22 | .upDownCounterBuilder("fully.qualified.updowncounter") 23 | .setDescription("Current length of widget processing queue") 24 | .setUnit("{widget}") 25 | // Uncomment to optionally change the type to double 26 | // .ofDoubles() 27 | .buildWithCallback( 28 | // the callback is invoked when a MetricReader reads metrics 29 | observableMeasurement -> { 30 | long currentWidgetCount = queueLength.get(); 31 | 32 | // Record a measurement with no attributes. 33 | // Attributes defaults to Attributes.empty(). 34 | observableMeasurement.record(currentWidgetCount); 35 | 36 | // Record a measurement with attributes, using pre-allocated attributes whenever 37 | // possible. 38 | observableMeasurement.record(currentWidgetCount, WIDGET_RED_CIRCLE); 39 | // Sometimes, attributes must be computed using application context. 40 | observableMeasurement.record( 41 | currentWidgetCount, 42 | Attributes.of( 43 | WIDGET_SHAPE, computeWidgetShape(), WIDGET_COLOR, computeWidgetColor())); 44 | }); 45 | 46 | // Optionally close the counter to unregister the callback when required 47 | asyncUpDownCounter.close(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /doc-snippets/api/src/main/java/otel/CounterUsage.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import static otel.Util.WIDGET_COLOR; 4 | import static otel.Util.WIDGET_SHAPE; 5 | import static otel.Util.computeWidgetColor; 6 | import static otel.Util.computeWidgetShape; 7 | import static otel.Util.customContext; 8 | 9 | import io.opentelemetry.api.common.Attributes; 10 | import io.opentelemetry.api.metrics.LongCounter; 11 | import io.opentelemetry.api.metrics.Meter; 12 | 13 | public class CounterUsage { 14 | private static final Attributes WIDGET_RED_CIRCLE = Util.WIDGET_RED_CIRCLE; 15 | 16 | public static void counterUsage(Meter meter) { 17 | // Construct a counter to record measurements that are always positive (monotonically 18 | // increasing). 19 | LongCounter counter = 20 | meter 21 | .counterBuilder("fully.qualified.counter") 22 | .setDescription("A count of produced widgets") 23 | .setUnit("{widget}") 24 | // optionally change the type to double 25 | // .ofDoubles() 26 | .build(); 27 | 28 | // Record a measurement with no attributes or context. 29 | // Attributes defaults to Attributes.empty(), context to Context.current(). 30 | counter.add(1L); 31 | 32 | // Record a measurement with attributes, using pre-allocated attributes whenever possible. 33 | counter.add(1L, WIDGET_RED_CIRCLE); 34 | // Sometimes, attributes must be computed using application context. 35 | counter.add( 36 | 1L, Attributes.of(WIDGET_SHAPE, computeWidgetShape(), WIDGET_COLOR, computeWidgetColor())); 37 | 38 | // Record a measurement with attributes, and context. 39 | // Most users will opt to omit the context argument, preferring the default Context.current(). 40 | counter.add(1L, WIDGET_RED_CIRCLE, customContext()); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /doc-snippets/api/src/main/java/otel/GaugeUsage.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import static otel.Util.WIDGET_COLOR; 4 | import static otel.Util.WIDGET_SHAPE; 5 | import static otel.Util.computeWidgetColor; 6 | import static otel.Util.computeWidgetShape; 7 | import static otel.Util.customContext; 8 | 9 | import io.opentelemetry.api.common.Attributes; 10 | import io.opentelemetry.api.metrics.DoubleGauge; 11 | import io.opentelemetry.api.metrics.Meter; 12 | 13 | public class GaugeUsage { 14 | private static final Attributes WIDGET_RED_CIRCLE = Util.WIDGET_RED_CIRCLE; 15 | 16 | public static void gaugeUsage(Meter meter) { 17 | // Construct a gauge to record measurements as they occur, which cannot be spatially 18 | // re-aggregated. 19 | DoubleGauge gauge = 20 | meter 21 | .gaugeBuilder("fully.qualified.gauge") 22 | .setDescription("The current temperature of the widget processing line") 23 | .setUnit("K") 24 | // Uncomment to optionally change the type to long 25 | // .ofLongs() 26 | .build(); 27 | 28 | // Record a measurement with no attributes or context. 29 | // Attributes defaults to Attributes.empty(), context to Context.current(). 30 | gauge.set(273.0); 31 | 32 | // Record a measurement with attributes, using pre-allocated attributes whenever possible. 33 | gauge.set(273.0, WIDGET_RED_CIRCLE); 34 | // Sometimes, attributes must be computed using application context. 35 | gauge.set( 36 | 273.0, 37 | Attributes.of(WIDGET_SHAPE, computeWidgetShape(), WIDGET_COLOR, computeWidgetColor())); 38 | 39 | // Record a measurement with attributes, and context. 40 | // Most users will opt to omit the context argument, preferring the default Context.current(). 41 | gauge.set(1L, WIDGET_RED_CIRCLE, customContext()); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /doc-snippets/api/src/main/java/otel/GlobalOpenTelemetryUsage.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.api.GlobalOpenTelemetry; 4 | import io.opentelemetry.api.OpenTelemetry; 5 | 6 | public class GlobalOpenTelemetryUsage { 7 | 8 | public static void openTelemetryUsage(OpenTelemetry openTelemetry) { 9 | // Set the GlobalOpenTelemetry instance as early in the application lifecycle as possible 10 | // Set must only be called once. Calling multiple times raises an exception. 11 | GlobalOpenTelemetry.set(openTelemetry); 12 | 13 | // Get the GlobalOpenTelemetry instance. 14 | openTelemetry = GlobalOpenTelemetry.get(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /doc-snippets/api/src/main/java/otel/HistogramUsage.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import static otel.Util.WIDGET_COLOR; 4 | import static otel.Util.WIDGET_SHAPE; 5 | import static otel.Util.computeWidgetColor; 6 | import static otel.Util.computeWidgetShape; 7 | import static otel.Util.customContext; 8 | 9 | import io.opentelemetry.api.common.Attributes; 10 | import io.opentelemetry.api.metrics.DoubleHistogram; 11 | import io.opentelemetry.api.metrics.Meter; 12 | 13 | public class HistogramUsage { 14 | private static final Attributes WIDGET_RED_CIRCLE = Util.WIDGET_RED_CIRCLE; 15 | 16 | public static void histogramUsage(Meter meter) { 17 | // Construct a histogram to record measurements where the distribution is important. 18 | DoubleHistogram histogram = 19 | meter 20 | .histogramBuilder("fully.qualified.histogram") 21 | .setDescription("Length of time to process a widget") 22 | .setUnit("s") 23 | // Uncomment to optionally provide advice on useful default explicit bucket boundaries 24 | // .setExplicitBucketBoundariesAdvice(Arrays.asList(1.0, 2.0, 3.0)) 25 | // Uncomment to optionally change the type to long 26 | // .ofLongs() 27 | .build(); 28 | 29 | // Record a measurement with no attributes or context. 30 | // Attributes defaults to Attributes.empty(), context to Context.current(). 31 | histogram.record(1.1); 32 | 33 | // Record a measurement with attributes, using pre-allocated attributes whenever possible. 34 | histogram.record(2.2, WIDGET_RED_CIRCLE); 35 | // Sometimes, attributes must be computed using application context. 36 | histogram.record( 37 | 3.2, Attributes.of(WIDGET_SHAPE, computeWidgetShape(), WIDGET_COLOR, computeWidgetColor())); 38 | 39 | // Record a measurement with attributes, and context. 40 | // Most users will opt to omit the context argument, preferring the default Context.current(). 41 | histogram.record(4.4, WIDGET_RED_CIRCLE, customContext()); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /doc-snippets/api/src/main/java/otel/InjectContextUsage.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.api.baggage.propagation.W3CBaggagePropagator; 4 | import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; 5 | import io.opentelemetry.context.Context; 6 | import io.opentelemetry.context.propagation.ContextPropagators; 7 | import io.opentelemetry.context.propagation.TextMapPropagator; 8 | import io.opentelemetry.context.propagation.TextMapSetter; 9 | import java.net.URI; 10 | import java.net.http.HttpClient; 11 | import java.net.http.HttpRequest; 12 | import java.net.http.HttpResponse; 13 | 14 | public class InjectContextUsage { 15 | private static final TextMapSetter TEXT_MAP_SETTER = new HttpRequestSetter(); 16 | 17 | public static void injectContextUsage() throws Exception { 18 | // Create a ContextPropagators instance which propagates w3c trace context and w3c baggage 19 | ContextPropagators propagators = 20 | ContextPropagators.create( 21 | TextMapPropagator.composite( 22 | W3CTraceContextPropagator.getInstance(), W3CBaggagePropagator.getInstance())); 23 | 24 | // Create an HttpRequest builder 25 | HttpClient httpClient = HttpClient.newBuilder().build(); 26 | HttpRequest.Builder requestBuilder = 27 | HttpRequest.newBuilder().uri(new URI("http://127.0.0.1:8080/resource")).GET(); 28 | 29 | // Given a ContextPropagators instance, inject the current context into the HTTP request carrier 30 | propagators.getTextMapPropagator().inject(Context.current(), requestBuilder, TEXT_MAP_SETTER); 31 | 32 | // Send the request with the injected context 33 | httpClient.send(requestBuilder.build(), HttpResponse.BodyHandlers.discarding()); 34 | } 35 | 36 | /** {@link TextMapSetter} with a {@link HttpRequest.Builder} carrier. */ 37 | private static class HttpRequestSetter implements TextMapSetter { 38 | @Override 39 | public void set(HttpRequest.Builder carrier, String key, String value) { 40 | if (carrier == null) { 41 | return; 42 | } 43 | carrier.setHeader(key, value); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /doc-snippets/api/src/main/java/otel/OpenTelemetryUsage.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.api.OpenTelemetry; 4 | import io.opentelemetry.api.common.Attributes; 5 | import io.opentelemetry.api.logs.LoggerProvider; 6 | import io.opentelemetry.api.metrics.MeterProvider; 7 | import io.opentelemetry.api.trace.TracerProvider; 8 | import io.opentelemetry.context.propagation.ContextPropagators; 9 | 10 | public class OpenTelemetryUsage { 11 | private static final Attributes WIDGET_RED_CIRCLE = Util.WIDGET_RED_CIRCLE; 12 | 13 | public static void openTelemetryUsage(OpenTelemetry openTelemetry) { 14 | // Access TracerProvider, MeterProvider, LoggerProvider, ContextPropagators 15 | TracerProvider tracerProvider = openTelemetry.getTracerProvider(); 16 | MeterProvider meterProvider = openTelemetry.getMeterProvider(); 17 | LoggerProvider loggerProvider = openTelemetry.getLogsBridge(); 18 | ContextPropagators propagators = openTelemetry.getPropagators(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /doc-snippets/api/src/main/java/otel/ProvidersAndScopes.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.api.OpenTelemetry; 4 | import io.opentelemetry.api.logs.Logger; 5 | import io.opentelemetry.api.logs.LoggerProvider; 6 | import io.opentelemetry.api.metrics.Meter; 7 | import io.opentelemetry.api.metrics.MeterProvider; 8 | import io.opentelemetry.api.trace.Tracer; 9 | import io.opentelemetry.api.trace.TracerProvider; 10 | 11 | public class ProvidersAndScopes { 12 | 13 | private static final String SCOPE_NAME = "fully.qualified.name"; 14 | private static final String SCOPE_VERSION = "1.0.0"; 15 | private static final String SCOPE_SCHEMA_URL = "https://example"; 16 | 17 | public static void providersUsage(OpenTelemetry openTelemetry) { 18 | // Access providers from an OpenTelemetry instance 19 | TracerProvider tracerProvider = openTelemetry.getTracerProvider(); 20 | MeterProvider meterProvider = openTelemetry.getMeterProvider(); 21 | // NOTE: LoggerProvider is a special case and should only be used to bridge logs from other 22 | // logging APIs / frameworks into OpenTelemetry. 23 | LoggerProvider loggerProvider = openTelemetry.getLogsBridge(); 24 | 25 | // Access tracer, meter, logger from providers to record telemetry for a particular scope 26 | Tracer tracer = 27 | tracerProvider 28 | .tracerBuilder(SCOPE_NAME) 29 | .setInstrumentationVersion(SCOPE_VERSION) 30 | .setSchemaUrl(SCOPE_SCHEMA_URL) 31 | .build(); 32 | Meter meter = 33 | meterProvider 34 | .meterBuilder(SCOPE_NAME) 35 | .setInstrumentationVersion(SCOPE_VERSION) 36 | .setSchemaUrl(SCOPE_SCHEMA_URL) 37 | .build(); 38 | Logger logger = 39 | loggerProvider 40 | .loggerBuilder(SCOPE_NAME) 41 | .setInstrumentationVersion(SCOPE_VERSION) 42 | .setSchemaUrl(SCOPE_SCHEMA_URL) 43 | .build(); 44 | 45 | // ...optionally, shorthand versions are available if scope version and schemaUrl aren't 46 | // available 47 | tracer = tracerProvider.get(SCOPE_NAME); 48 | meter = meterProvider.get(SCOPE_NAME); 49 | logger = loggerProvider.get(SCOPE_NAME); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /doc-snippets/api/src/main/java/otel/SemanticAttributesUsage.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.api.common.Attributes; 4 | import io.opentelemetry.semconv.HttpAttributes; 5 | import io.opentelemetry.semconv.ServerAttributes; 6 | import io.opentelemetry.semconv.incubating.HttpIncubatingAttributes; 7 | 8 | public class SemanticAttributesUsage { 9 | public static void semanticAttributesUsage() { 10 | // Semantic attributes are organized by top-level domain and whether they are stable or 11 | // incubating. 12 | // For example: 13 | // - stable attributes starting with http.* are in the HttpAttributes class. 14 | // - stable attributes starting with server.* are in the ServerAttributes class. 15 | // - incubating attributes starting with http.* are in the HttpIncubatingAttributes class. 16 | // Attribute keys which define an enumeration of values are accessible in an inner 17 | // {AttributeKey}Values class. 18 | // For example, the enumeration of http.request.method values is available in the 19 | // HttpAttributes.HttpRequestMethodValues class. 20 | Attributes attributes = 21 | Attributes.builder() 22 | .put(HttpAttributes.HTTP_REQUEST_METHOD, HttpAttributes.HttpRequestMethodValues.GET) 23 | .put(HttpAttributes.HTTP_ROUTE, "/users/:id") 24 | .put(ServerAttributes.SERVER_ADDRESS, "example") 25 | .put(ServerAttributes.SERVER_PORT, 8080L) 26 | .put(HttpIncubatingAttributes.HTTP_RESPONSE_BODY_SIZE, 1024) 27 | .build(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /doc-snippets/api/src/main/java/otel/SpanAndContextUsage.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.api.trace.Span; 4 | import io.opentelemetry.api.trace.Tracer; 5 | import io.opentelemetry.context.Context; 6 | import io.opentelemetry.context.Scope; 7 | 8 | public class SpanAndContextUsage { 9 | private final Tracer tracer; 10 | 11 | SpanAndContextUsage(Tracer tracer) { 12 | this.tracer = tracer; 13 | } 14 | 15 | public void nestedSpanUsage() { 16 | // Start a span. Since we don't call makeCurrent(), we must explicitly call setParent on 17 | // children. Wrap code in try / finally to ensure we end the span. 18 | Span span = tracer.spanBuilder("span").startSpan(); 19 | try { 20 | // Start a child span, explicitly setting the parent. 21 | Span childSpan = 22 | tracer 23 | .spanBuilder("span child") 24 | // Explicitly set parent. 25 | .setParent(span.storeInContext(Context.current())) 26 | .startSpan(); 27 | // Call makeCurrent(), adding childSpan to Context.current(). Spans created inside the scope 28 | // will have their parent set to childSpan. 29 | try (Scope childSpanScope = childSpan.makeCurrent()) { 30 | // Call another method which creates a span. The span's parent will be childSpan since it is 31 | // started in the childSpan scope. 32 | doWork(); 33 | } finally { 34 | childSpan.end(); 35 | } 36 | } finally { 37 | span.end(); 38 | } 39 | } 40 | 41 | private int doWork() { 42 | Span doWorkSpan = tracer.spanBuilder("doWork").startSpan(); 43 | try (Scope scope = doWorkSpan.makeCurrent()) { 44 | int result = 0; 45 | for (int i = 0; i < 10; i++) { 46 | result += i; 47 | } 48 | return result; 49 | } finally { 50 | doWorkSpan.end(); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /doc-snippets/api/src/main/java/otel/UpDownCounterUsage.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import static otel.Util.WIDGET_COLOR; 4 | import static otel.Util.WIDGET_SHAPE; 5 | import static otel.Util.computeWidgetColor; 6 | import static otel.Util.computeWidgetShape; 7 | import static otel.Util.customContext; 8 | 9 | import io.opentelemetry.api.common.Attributes; 10 | import io.opentelemetry.api.metrics.LongUpDownCounter; 11 | import io.opentelemetry.api.metrics.Meter; 12 | 13 | public class UpDownCounterUsage { 14 | 15 | private static final Attributes WIDGET_RED_CIRCLE = Util.WIDGET_RED_CIRCLE; 16 | 17 | public static void usage(Meter meter) { 18 | // Construct an updowncounter to record measurements that go up and down. 19 | LongUpDownCounter upDownCounter = 20 | meter 21 | .upDownCounterBuilder("fully.qualified.updowncounter") 22 | .setDescription("Current length of widget processing queue") 23 | .setUnit("{widget}") 24 | // Uncomment to optionally change the type to double 25 | // .ofDoubles() 26 | .build(); 27 | 28 | // Record a measurement with no attributes or context. 29 | // Attributes defaults to Attributes.empty(), context to Context.current(). 30 | upDownCounter.add(1L); 31 | 32 | // Record a measurement with attributes, using pre-allocated attributes whenever possible. 33 | upDownCounter.add(-1L, WIDGET_RED_CIRCLE); 34 | // Sometimes, attributes must be computed using application context. 35 | upDownCounter.add( 36 | -1L, Attributes.of(WIDGET_SHAPE, computeWidgetShape(), WIDGET_COLOR, computeWidgetColor())); 37 | 38 | // Record a measurement with attributes, and context. 39 | // Most users will opt to omit the context argument, preferring the default Context.current(). 40 | upDownCounter.add(1L, WIDGET_RED_CIRCLE, customContext()); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /doc-snippets/api/src/main/java/otel/Util.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.api.common.AttributeKey; 4 | import io.opentelemetry.api.common.Attributes; 5 | import io.opentelemetry.context.Context; 6 | import io.opentelemetry.context.ContextKey; 7 | import java.util.Random; 8 | 9 | class Util { 10 | 11 | private static final ContextKey SHAPE_CONTEXT_KEY = ContextKey.named("shape"); 12 | private static final Random random = new Random(); 13 | 14 | static final AttributeKey WIDGET_SHAPE = AttributeKey.stringKey("com.acme.widget.shape"); 15 | static final AttributeKey WIDGET_COLOR = AttributeKey.stringKey("com.acme.widget.color"); 16 | 17 | static final Attributes WIDGET_RED_SQUARE = 18 | Attributes.of(WIDGET_SHAPE, "square", WIDGET_COLOR, "red"); 19 | static final Attributes WIDGET_RED_CIRCLE = 20 | Attributes.of(WIDGET_SHAPE, "circle", WIDGET_COLOR, "circle"); 21 | 22 | static String computeWidgetShape() { 23 | return random.nextBoolean() ? "circle" : "square"; 24 | } 25 | 26 | static String computeWidgetColor() { 27 | return random.nextBoolean() ? "red" : "blue"; 28 | } 29 | 30 | static Context customContext() { 31 | return Context.current().with(SHAPE_CONTEXT_KEY, computeWidgetShape()); 32 | } 33 | 34 | private Util() {} 35 | } 36 | -------------------------------------------------------------------------------- /doc-snippets/configuration/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("java") 3 | } 4 | 5 | val moduleName by extra { "io.opentelemetry.examples.docs.configuration" } 6 | 7 | dependencies { 8 | implementation("io.opentelemetry:opentelemetry-sdk") 9 | implementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure") 10 | 11 | implementation("io.opentelemetry:opentelemetry-exporter-otlp") 12 | implementation("io.opentelemetry:opentelemetry-exporter-logging") 13 | implementation("io.opentelemetry:opentelemetry-exporter-logging-otlp") 14 | implementation("io.opentelemetry:opentelemetry-exporter-zipkin") 15 | implementation("io.opentelemetry:opentelemetry-exporter-prometheus") 16 | implementation("io.opentelemetry:opentelemetry-sdk-extension-jaeger-remote-sampler") 17 | 18 | implementation("io.opentelemetry.semconv:opentelemetry-semconv") 19 | implementation("io.opentelemetry.semconv:opentelemetry-semconv-incubating:1.32.0-alpha") 20 | } 21 | -------------------------------------------------------------------------------- /doc-snippets/configuration/src/main/java/otel/AutoConfiguredSdk.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.sdk.OpenTelemetrySdk; 4 | import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; 5 | 6 | public class AutoConfiguredSdk { 7 | public static OpenTelemetrySdk autoconfiguredSdk() { 8 | return AutoConfiguredOpenTelemetrySdk.initialize().getOpenTelemetrySdk(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /doc-snippets/configuration/src/main/java/otel/ContextPropagatorsConfig.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.api.baggage.propagation.W3CBaggagePropagator; 4 | import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; 5 | import io.opentelemetry.context.propagation.ContextPropagators; 6 | import io.opentelemetry.context.propagation.TextMapPropagator; 7 | 8 | public class ContextPropagatorsConfig { 9 | public static ContextPropagators create() { 10 | return ContextPropagators.create( 11 | TextMapPropagator.composite( 12 | W3CTraceContextPropagator.getInstance(), W3CBaggagePropagator.getInstance())); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /doc-snippets/configuration/src/main/java/otel/CustomLogRecordExporter.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.sdk.common.CompletableResultCode; 4 | import io.opentelemetry.sdk.logs.data.LogRecordData; 5 | import io.opentelemetry.sdk.logs.export.LogRecordExporter; 6 | import java.util.Collection; 7 | import java.util.logging.Level; 8 | import java.util.logging.Logger; 9 | 10 | public class CustomLogRecordExporter implements LogRecordExporter { 11 | 12 | private static final Logger logger = Logger.getLogger(CustomLogRecordExporter.class.getName()); 13 | 14 | @Override 15 | public CompletableResultCode export(Collection logs) { 16 | // Export the records. Typically, records are sent out of process via some network protocol, but 17 | // we simply log for illustrative purposes. 18 | System.out.println("Exporting logs"); 19 | logs.forEach(log -> System.out.println("log record: " + log)); 20 | return CompletableResultCode.ofSuccess(); 21 | } 22 | 23 | @Override 24 | public CompletableResultCode flush() { 25 | // Export any records which have been queued up but not yet exported. 26 | logger.log(Level.INFO, "flushing"); 27 | return CompletableResultCode.ofSuccess(); 28 | } 29 | 30 | @Override 31 | public CompletableResultCode shutdown() { 32 | // Shutdown the exporter and cleanup any resources. 33 | logger.log(Level.INFO, "shutting down"); 34 | return CompletableResultCode.ofSuccess(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /doc-snippets/configuration/src/main/java/otel/CustomLogRecordExporterProvider.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; 4 | import io.opentelemetry.sdk.autoconfigure.spi.logs.ConfigurableLogRecordExporterProvider; 5 | import io.opentelemetry.sdk.logs.export.LogRecordExporter; 6 | 7 | public class CustomLogRecordExporterProvider implements ConfigurableLogRecordExporterProvider { 8 | 9 | @Override 10 | public LogRecordExporter createExporter(ConfigProperties config) { 11 | // Callback invoked when OTEL_LOGS_EXPORTER includes the value from getName(). 12 | return new CustomLogRecordExporter(); 13 | } 14 | 15 | @Override 16 | public String getName() { 17 | return "custom-exporter"; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /doc-snippets/configuration/src/main/java/otel/CustomLogRecordProcessor.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.api.common.AttributeKey; 4 | import io.opentelemetry.context.Context; 5 | import io.opentelemetry.sdk.common.CompletableResultCode; 6 | import io.opentelemetry.sdk.logs.LogRecordProcessor; 7 | import io.opentelemetry.sdk.logs.ReadWriteLogRecord; 8 | 9 | public class CustomLogRecordProcessor implements LogRecordProcessor { 10 | 11 | @Override 12 | public void onEmit(Context context, ReadWriteLogRecord logRecord) { 13 | // Callback invoked when log record is emitted. 14 | // Enrich the record with a custom attribute. 15 | logRecord.setAttribute(AttributeKey.stringKey("my.custom.attribute"), "hello world"); 16 | } 17 | 18 | @Override 19 | public CompletableResultCode shutdown() { 20 | // Optionally shutdown the processor and cleanup any resources. 21 | return CompletableResultCode.ofSuccess(); 22 | } 23 | 24 | @Override 25 | public CompletableResultCode forceFlush() { 26 | // Optionally process any records which have been queued up but not yet processed. 27 | return CompletableResultCode.ofSuccess(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /doc-snippets/configuration/src/main/java/otel/CustomMetricExporter.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.sdk.common.CompletableResultCode; 4 | import io.opentelemetry.sdk.common.export.MemoryMode; 5 | import io.opentelemetry.sdk.metrics.Aggregation; 6 | import io.opentelemetry.sdk.metrics.InstrumentType; 7 | import io.opentelemetry.sdk.metrics.data.AggregationTemporality; 8 | import io.opentelemetry.sdk.metrics.data.MetricData; 9 | import io.opentelemetry.sdk.metrics.export.AggregationTemporalitySelector; 10 | import io.opentelemetry.sdk.metrics.export.MetricExporter; 11 | import java.util.Collection; 12 | import java.util.logging.Level; 13 | import java.util.logging.Logger; 14 | 15 | public class CustomMetricExporter implements MetricExporter { 16 | 17 | private static final Logger logger = Logger.getLogger(CustomMetricExporter.class.getName()); 18 | 19 | @Override 20 | public CompletableResultCode export(Collection metrics) { 21 | // Export the records. Typically, records are sent out of process via some network protocol, but 22 | // we simply log for illustrative purposes. 23 | logger.log(Level.INFO, "Exporting metrics"); 24 | metrics.forEach(metric -> logger.log(Level.INFO, "Metric: " + metric)); 25 | return CompletableResultCode.ofSuccess(); 26 | } 27 | 28 | @Override 29 | public CompletableResultCode flush() { 30 | // Export any records which have been queued up but not yet exported. 31 | logger.log(Level.INFO, "flushing"); 32 | return CompletableResultCode.ofSuccess(); 33 | } 34 | 35 | @Override 36 | public CompletableResultCode shutdown() { 37 | // Shutdown the exporter and cleanup any resources. 38 | logger.log(Level.INFO, "shutting down"); 39 | return CompletableResultCode.ofSuccess(); 40 | } 41 | 42 | @Override 43 | public AggregationTemporality getAggregationTemporality(InstrumentType instrumentType) { 44 | // Specify the required aggregation temporality as a function of instrument type 45 | return AggregationTemporalitySelector.deltaPreferred() 46 | .getAggregationTemporality(instrumentType); 47 | } 48 | 49 | @Override 50 | public MemoryMode getMemoryMode() { 51 | // Optionally specify the memory mode, indicating whether metric records can be reused or must 52 | // be immutable 53 | return MemoryMode.REUSABLE_DATA; 54 | } 55 | 56 | @Override 57 | public Aggregation getDefaultAggregation(InstrumentType instrumentType) { 58 | // Optionally specify the default aggregation as a function of instrument kind 59 | return Aggregation.defaultAggregation(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /doc-snippets/configuration/src/main/java/otel/CustomMetricExporterProvider.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; 4 | import io.opentelemetry.sdk.autoconfigure.spi.metrics.ConfigurableMetricExporterProvider; 5 | import io.opentelemetry.sdk.metrics.export.MetricExporter; 6 | 7 | public class CustomMetricExporterProvider implements ConfigurableMetricExporterProvider { 8 | 9 | @Override 10 | public MetricExporter createExporter(ConfigProperties config) { 11 | // Callback invoked when OTEL_METRICS_EXPORTER includes the value from getName(). 12 | return new CustomMetricExporter(); 13 | } 14 | 15 | @Override 16 | public String getName() { 17 | return "custom-exporter"; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /doc-snippets/configuration/src/main/java/otel/CustomResourceProvider.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; 4 | import io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider; 5 | import io.opentelemetry.sdk.resources.Resource; 6 | 7 | public class CustomResourceProvider implements ResourceProvider { 8 | 9 | @Override 10 | public Resource createResource(ConfigProperties config) { 11 | // Callback invoked to contribute to the resource. 12 | return Resource.builder().put("my.custom.resource.attribute", "abc123").build(); 13 | } 14 | 15 | @Override 16 | public int order() { 17 | // Optionally influence the order of invocation. 18 | return 0; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /doc-snippets/configuration/src/main/java/otel/CustomSampler.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.api.common.Attributes; 4 | import io.opentelemetry.api.trace.SpanKind; 5 | import io.opentelemetry.context.Context; 6 | import io.opentelemetry.sdk.trace.data.LinkData; 7 | import io.opentelemetry.sdk.trace.samplers.Sampler; 8 | import io.opentelemetry.sdk.trace.samplers.SamplingResult; 9 | import java.util.List; 10 | 11 | public class CustomSampler implements Sampler { 12 | @Override 13 | public SamplingResult shouldSample( 14 | Context parentContext, 15 | String traceId, 16 | String name, 17 | SpanKind spanKind, 18 | Attributes attributes, 19 | List parentLinks) { 20 | // Callback invoked when span is started, before any SpanProcessor is called. 21 | // If the SamplingDecision is: 22 | // - DROP: the span is dropped. A valid span context is created and SpanProcessor#onStart is 23 | // still called, but no data is recorded and SpanProcessor#onEnd is not called. 24 | // - RECORD_ONLY: the span is recorded but not sampled. Data is recorded to the span, 25 | // SpanProcessor#onStart and SpanProcessor#onEnd are called, but the span's sampled status 26 | // indicates it should not be exported out of process. 27 | // - RECORD_AND_SAMPLE: the span is recorded and sampled. Data is recorded to the span, 28 | // SpanProcessor#onStart and SpanProcessor#onEnd are called, and the span's sampled status 29 | // indicates it should be exported out of process. 30 | return SpanKind.SERVER == spanKind ? SamplingResult.recordAndSample() : SamplingResult.drop(); 31 | } 32 | 33 | @Override 34 | public String getDescription() { 35 | // Return a description of the sampler. 36 | return this.getClass().getSimpleName(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /doc-snippets/configuration/src/main/java/otel/CustomSamplerProvider.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; 4 | import io.opentelemetry.sdk.autoconfigure.spi.traces.ConfigurableSamplerProvider; 5 | import io.opentelemetry.sdk.trace.samplers.Sampler; 6 | 7 | public class CustomSamplerProvider implements ConfigurableSamplerProvider { 8 | 9 | @Override 10 | public Sampler createSampler(ConfigProperties config) { 11 | // Callback invoked when OTEL_TRACES_SAMPLER is set to the value from getName(). 12 | return new CustomSampler(); 13 | } 14 | 15 | @Override 16 | public String getName() { 17 | return "custom-sampler"; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /doc-snippets/configuration/src/main/java/otel/CustomSpanExporter.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.sdk.common.CompletableResultCode; 4 | import io.opentelemetry.sdk.trace.data.SpanData; 5 | import io.opentelemetry.sdk.trace.export.SpanExporter; 6 | import java.util.Collection; 7 | import java.util.logging.Level; 8 | import java.util.logging.Logger; 9 | 10 | public class CustomSpanExporter implements SpanExporter { 11 | 12 | private static final Logger logger = Logger.getLogger(CustomSpanExporter.class.getName()); 13 | 14 | @Override 15 | public CompletableResultCode export(Collection spans) { 16 | // Export the records. Typically, records are sent out of process via some network protocol, but 17 | // we simply log for illustrative purposes. 18 | logger.log(Level.INFO, "Exporting spans"); 19 | spans.forEach(span -> logger.log(Level.INFO, "Span: " + span)); 20 | return CompletableResultCode.ofSuccess(); 21 | } 22 | 23 | @Override 24 | public CompletableResultCode flush() { 25 | // Export any records which have been queued up but not yet exported. 26 | logger.log(Level.INFO, "flushing"); 27 | return CompletableResultCode.ofSuccess(); 28 | } 29 | 30 | @Override 31 | public CompletableResultCode shutdown() { 32 | // Shutdown the exporter and cleanup any resources. 33 | logger.log(Level.INFO, "shutting down"); 34 | return CompletableResultCode.ofSuccess(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /doc-snippets/configuration/src/main/java/otel/CustomSpanExporterProvider.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; 4 | import io.opentelemetry.sdk.autoconfigure.spi.traces.ConfigurableSpanExporterProvider; 5 | import io.opentelemetry.sdk.trace.export.SpanExporter; 6 | 7 | public class CustomSpanExporterProvider implements ConfigurableSpanExporterProvider { 8 | 9 | @Override 10 | public SpanExporter createExporter(ConfigProperties config) { 11 | // Callback invoked when OTEL_TRACES_EXPORTER includes the value from getName(). 12 | return new CustomSpanExporter(); 13 | } 14 | 15 | @Override 16 | public String getName() { 17 | return "custom-exporter"; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /doc-snippets/configuration/src/main/java/otel/CustomSpanProcessor.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.context.Context; 4 | import io.opentelemetry.sdk.common.CompletableResultCode; 5 | import io.opentelemetry.sdk.trace.ReadWriteSpan; 6 | import io.opentelemetry.sdk.trace.ReadableSpan; 7 | import io.opentelemetry.sdk.trace.SpanProcessor; 8 | 9 | public class CustomSpanProcessor implements SpanProcessor { 10 | 11 | @Override 12 | public void onStart(Context parentContext, ReadWriteSpan span) { 13 | // Callback invoked when span is started. 14 | // Enrich the record with a custom attribute. 15 | span.setAttribute("my.custom.attribute", "hello world"); 16 | } 17 | 18 | @Override 19 | public boolean isStartRequired() { 20 | // Indicate if onStart should be called. 21 | return true; 22 | } 23 | 24 | @Override 25 | public void onEnd(ReadableSpan span) { 26 | // Callback invoked when span is ended. 27 | } 28 | 29 | @Override 30 | public boolean isEndRequired() { 31 | // Indicate if onEnd should be called. 32 | return false; 33 | } 34 | 35 | @Override 36 | public CompletableResultCode shutdown() { 37 | // Optionally shutdown the processor and cleanup any resources. 38 | return CompletableResultCode.ofSuccess(); 39 | } 40 | 41 | @Override 42 | public CompletableResultCode forceFlush() { 43 | // Optionally process any records which have been queued up but not yet processed. 44 | return CompletableResultCode.ofSuccess(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /doc-snippets/configuration/src/main/java/otel/CustomTextMapPropagator.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.context.Context; 4 | import io.opentelemetry.context.propagation.TextMapGetter; 5 | import io.opentelemetry.context.propagation.TextMapPropagator; 6 | import io.opentelemetry.context.propagation.TextMapSetter; 7 | import java.util.Collection; 8 | import java.util.Collections; 9 | 10 | public class CustomTextMapPropagator implements TextMapPropagator { 11 | 12 | @Override 13 | public Collection fields() { 14 | // Return fields used for propagation. See W3CTraceContextPropagator for reference 15 | // implementation. 16 | return Collections.emptyList(); 17 | } 18 | 19 | @Override 20 | public void inject(Context context, C carrier, TextMapSetter setter) { 21 | // Inject context. See W3CTraceContextPropagator for reference implementation. 22 | } 23 | 24 | @Override 25 | public Context extract(Context context, C carrier, TextMapGetter getter) { 26 | // Extract context. See W3CTraceContextPropagator for reference implementation. 27 | return context; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /doc-snippets/configuration/src/main/java/otel/CustomTextMapPropagatorProvider.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.context.propagation.TextMapPropagator; 4 | import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; 5 | import io.opentelemetry.sdk.autoconfigure.spi.ConfigurablePropagatorProvider; 6 | 7 | public class CustomTextMapPropagatorProvider implements ConfigurablePropagatorProvider { 8 | @Override 9 | public TextMapPropagator getPropagator(ConfigProperties config) { 10 | // Callback invoked when OTEL_PROPAGATORS includes the value from getName(). 11 | return new CustomTextMapPropagator(); 12 | } 13 | 14 | @Override 15 | public String getName() { 16 | return "custom-propagator"; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /doc-snippets/configuration/src/main/java/otel/CustomizedAutoConfiguredSdk.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.sdk.OpenTelemetrySdk; 4 | import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; 5 | import java.util.Collections; 6 | 7 | public class CustomizedAutoConfiguredSdk { 8 | public static OpenTelemetrySdk autoconfiguredSdk() { 9 | return AutoConfiguredOpenTelemetrySdk.builder() 10 | // Optionally customize TextMapPropagator. 11 | .addPropagatorCustomizer((textMapPropagator, configProperties) -> textMapPropagator) 12 | // Optionally customize Resource. 13 | .addResourceCustomizer((resource, configProperties) -> resource) 14 | // Optionally customize Sampler. 15 | .addSamplerCustomizer((sampler, configProperties) -> sampler) 16 | // Optionally customize SpanExporter. 17 | .addSpanExporterCustomizer((spanExporter, configProperties) -> spanExporter) 18 | // Optionally customize SpanProcessor. 19 | .addSpanProcessorCustomizer((spanProcessor, configProperties) -> spanProcessor) 20 | // Optionally supply additional properties. 21 | .addPropertiesSupplier(Collections::emptyMap) 22 | // Optionally customize ConfigProperties. 23 | .addPropertiesCustomizer(configProperties -> Collections.emptyMap()) 24 | // Optionally customize SdkTracerProviderBuilder. 25 | .addTracerProviderCustomizer((builder, configProperties) -> builder) 26 | // Optionally customize SdkMeterProviderBuilder. 27 | .addMeterProviderCustomizer((builder, configProperties) -> builder) 28 | // Optionally customize MetricExporter. 29 | .addMetricExporterCustomizer((metricExporter, configProperties) -> metricExporter) 30 | // Optionally customize MetricReader. 31 | .addMetricReaderCustomizer((metricReader, configProperties) -> metricReader) 32 | // Optionally customize SdkLoggerProviderBuilder. 33 | .addLoggerProviderCustomizer((builder, configProperties) -> builder) 34 | // Optionally customize LogRecordExporter. 35 | .addLogRecordExporterCustomizer((logRecordExporter, configProperties) -> logRecordExporter) 36 | // Optionally customize LogRecordProcessor. 37 | .addLogRecordProcessorCustomizer((processor, configProperties) -> processor) 38 | .build() 39 | .getOpenTelemetrySdk(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /doc-snippets/configuration/src/main/java/otel/CustomizerProvider.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizer; 4 | import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider; 5 | import java.util.Collections; 6 | 7 | public class CustomizerProvider implements AutoConfigurationCustomizerProvider { 8 | 9 | @Override 10 | public void customize(AutoConfigurationCustomizer customizer) { 11 | // Optionally customize TextMapPropagator. 12 | customizer.addPropagatorCustomizer((textMapPropagator, configProperties) -> textMapPropagator); 13 | // Optionally customize Resource. 14 | customizer.addResourceCustomizer((resource, configProperties) -> resource); 15 | // Optionally customize Sampler. 16 | customizer.addSamplerCustomizer((sampler, configProperties) -> sampler); 17 | // Optionally customize SpanExporter. 18 | customizer.addSpanExporterCustomizer((spanExporter, configProperties) -> spanExporter); 19 | // Optionally customize SpanProcessor. 20 | customizer.addSpanProcessorCustomizer((spanProcessor, configProperties) -> spanProcessor); 21 | // Optionally supply additional properties. 22 | customizer.addPropertiesSupplier(Collections::emptyMap); 23 | // Optionally customize ConfigProperties. 24 | customizer.addPropertiesCustomizer(configProperties -> Collections.emptyMap()); 25 | // Optionally customize SdkTracerProviderBuilder. 26 | customizer.addTracerProviderCustomizer((builder, configProperties) -> builder); 27 | // Optionally customize SdkMeterProviderBuilder. 28 | customizer.addMeterProviderCustomizer((builder, configProperties) -> builder); 29 | // Optionally customize MetricExporter. 30 | customizer.addMetricExporterCustomizer((metricExporter, configProperties) -> metricExporter); 31 | // Optionally customize MetricReader. 32 | customizer.addMetricReaderCustomizer((metricReader, configProperties) -> metricReader); 33 | // Optionally customize SdkLoggerProviderBuilder. 34 | customizer.addLoggerProviderCustomizer((builder, configProperties) -> builder); 35 | // Optionally customize LogRecordExporter. 36 | customizer.addLogRecordExporterCustomizer((exporter, configProperties) -> exporter); 37 | // Optionally customize LogRecordProcessor. 38 | customizer.addLogRecordProcessorCustomizer((processor, configProperties) -> processor); 39 | } 40 | 41 | @Override 42 | public int order() { 43 | // Optionally influence the order of invocation. 44 | return 0; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /doc-snippets/configuration/src/main/java/otel/LogLimitsConfig.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.sdk.logs.LogLimits; 4 | 5 | public class LogLimitsConfig { 6 | public static LogLimits logLimits() { 7 | return LogLimits.builder() 8 | .setMaxNumberOfAttributes(128) 9 | .setMaxAttributeValueLength(1024) 10 | .build(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /doc-snippets/configuration/src/main/java/otel/LogRecordExporterConfig.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.exporter.logging.SystemOutLogRecordExporter; 4 | import io.opentelemetry.exporter.logging.otlp.OtlpJsonLoggingLogRecordExporter; 5 | import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter; 6 | import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporter; 7 | import io.opentelemetry.sdk.logs.export.LogRecordExporter; 8 | import java.time.Duration; 9 | 10 | public class LogRecordExporterConfig { 11 | public static LogRecordExporter otlpHttpLogRecordExporter(String endpoint) { 12 | return OtlpHttpLogRecordExporter.builder() 13 | .setEndpoint(endpoint) 14 | .addHeader("api-key", "value") 15 | .setTimeout(Duration.ofSeconds(10)) 16 | .build(); 17 | } 18 | 19 | public static LogRecordExporter otlpGrpcLogRecordExporter(String endpoint) { 20 | return OtlpGrpcLogRecordExporter.builder() 21 | .setEndpoint(endpoint) 22 | .addHeader("api-key", "value") 23 | .setTimeout(Duration.ofSeconds(10)) 24 | .build(); 25 | } 26 | 27 | public static LogRecordExporter systemOutLogRecordExporter() { 28 | return SystemOutLogRecordExporter.create(); 29 | } 30 | 31 | public static LogRecordExporter otlpJsonLoggingLogRecordExporter() { 32 | return OtlpJsonLoggingLogRecordExporter.create(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /doc-snippets/configuration/src/main/java/otel/LogRecordProcessorConfig.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.sdk.logs.LogRecordProcessor; 4 | import io.opentelemetry.sdk.logs.export.BatchLogRecordProcessor; 5 | import io.opentelemetry.sdk.logs.export.LogRecordExporter; 6 | import io.opentelemetry.sdk.logs.export.SimpleLogRecordProcessor; 7 | import java.time.Duration; 8 | 9 | public class LogRecordProcessorConfig { 10 | public static LogRecordProcessor batchLogRecordProcessor(LogRecordExporter logRecordExporter) { 11 | return BatchLogRecordProcessor.builder(logRecordExporter) 12 | .setMaxQueueSize(2048) 13 | .setExporterTimeout(Duration.ofSeconds(30)) 14 | .setScheduleDelay(Duration.ofSeconds(1)) 15 | .build(); 16 | } 17 | 18 | public static LogRecordProcessor simpleLogRecordProcessor(LogRecordExporter logRecordExporter) { 19 | return SimpleLogRecordProcessor.create(logRecordExporter); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /doc-snippets/configuration/src/main/java/otel/MetricExporterConfig.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.exporter.logging.LoggingMetricExporter; 4 | import io.opentelemetry.exporter.logging.otlp.OtlpJsonLoggingMetricExporter; 5 | import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter; 6 | import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporter; 7 | import io.opentelemetry.sdk.metrics.export.MetricExporter; 8 | import java.time.Duration; 9 | 10 | public class MetricExporterConfig { 11 | public static MetricExporter otlpHttpMetricExporter(String endpoint) { 12 | return OtlpHttpMetricExporter.builder() 13 | .setEndpoint(endpoint) 14 | .addHeader("api-key", "value") 15 | .setTimeout(Duration.ofSeconds(10)) 16 | .build(); 17 | } 18 | 19 | public static MetricExporter otlpGrpcMetricExporter(String endpoint) { 20 | return OtlpGrpcMetricExporter.builder() 21 | .setEndpoint(endpoint) 22 | .addHeader("api-key", "value") 23 | .setTimeout(Duration.ofSeconds(10)) 24 | .build(); 25 | } 26 | 27 | public static MetricExporter logginMetricExporter() { 28 | return LoggingMetricExporter.create(); 29 | } 30 | 31 | public static MetricExporter otlpJsonLoggingMetricExporter() { 32 | return OtlpJsonLoggingMetricExporter.create(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /doc-snippets/configuration/src/main/java/otel/MetricReaderConfig.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.exporter.prometheus.PrometheusHttpServer; 4 | import io.opentelemetry.sdk.metrics.export.MetricExporter; 5 | import io.opentelemetry.sdk.metrics.export.MetricReader; 6 | import io.opentelemetry.sdk.metrics.export.PeriodicMetricReader; 7 | import java.time.Duration; 8 | 9 | public class MetricReaderConfig { 10 | public static MetricReader periodicMetricReader(MetricExporter metricExporter) { 11 | return PeriodicMetricReader.builder(metricExporter).setInterval(Duration.ofSeconds(60)).build(); 12 | } 13 | 14 | public static MetricReader prometheusMetricReader() { 15 | return PrometheusHttpServer.builder().setHost("localhost").setPort(9464).build(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /doc-snippets/configuration/src/main/java/otel/OpenTelemetrySdkConfig.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.sdk.OpenTelemetrySdk; 4 | import io.opentelemetry.sdk.resources.Resource; 5 | 6 | public class OpenTelemetrySdkConfig { 7 | public static OpenTelemetrySdk create() { 8 | Resource resource = ResourceConfig.create(); 9 | return OpenTelemetrySdk.builder() 10 | .setTracerProvider(SdkTracerProviderConfig.create(resource)) 11 | .setMeterProvider(SdkMeterProviderConfig.create(resource)) 12 | .setLoggerProvider(SdkLoggerProviderConfig.create(resource)) 13 | .setPropagators(ContextPropagatorsConfig.create()) 14 | .build(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /doc-snippets/configuration/src/main/java/otel/ResourceConfig.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.sdk.resources.Resource; 4 | import io.opentelemetry.semconv.ServiceAttributes; 5 | 6 | public class ResourceConfig { 7 | public static Resource create() { 8 | return Resource.getDefault().toBuilder() 9 | .put(ServiceAttributes.SERVICE_NAME, "my-service") 10 | .build(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /doc-snippets/configuration/src/main/java/otel/SamplerConfig.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.sdk.extension.trace.jaeger.sampler.JaegerRemoteSampler; 4 | import io.opentelemetry.sdk.trace.samplers.Sampler; 5 | import java.time.Duration; 6 | 7 | public class SamplerConfig { 8 | public static Sampler parentBasedSampler(Sampler root) { 9 | return Sampler.parentBasedBuilder(root) 10 | .setLocalParentNotSampled(Sampler.alwaysOff()) 11 | .setLocalParentSampled(Sampler.alwaysOn()) 12 | .setRemoteParentNotSampled(Sampler.alwaysOff()) 13 | .setRemoteParentSampled(Sampler.alwaysOn()) 14 | .build(); 15 | } 16 | 17 | public static Sampler alwaysOn() { 18 | return Sampler.alwaysOn(); 19 | } 20 | 21 | public static Sampler alwaysOff() { 22 | return Sampler.alwaysOff(); 23 | } 24 | 25 | public static Sampler traceIdRatioBased(double ratio) { 26 | return Sampler.traceIdRatioBased(ratio); 27 | } 28 | 29 | public static Sampler jaegerRemoteSampler() { 30 | return JaegerRemoteSampler.builder() 31 | .setInitialSampler(Sampler.alwaysOn()) 32 | .setEndpoint("http://endpoint") 33 | .setPollingInterval(Duration.ofSeconds(60)) 34 | .setServiceName("my-service-name") 35 | .build(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /doc-snippets/configuration/src/main/java/otel/SdkLoggerProviderConfig.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.sdk.logs.SdkLoggerProvider; 4 | import io.opentelemetry.sdk.resources.Resource; 5 | 6 | public class SdkLoggerProviderConfig { 7 | public static SdkLoggerProvider create(Resource resource) { 8 | return SdkLoggerProvider.builder() 9 | .setResource(resource) 10 | .addLogRecordProcessor( 11 | LogRecordProcessorConfig.batchLogRecordProcessor( 12 | LogRecordExporterConfig.otlpHttpLogRecordExporter("http://localhost:4318/v1/logs"))) 13 | .setLogLimits(LogLimitsConfig::logLimits) 14 | .build(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /doc-snippets/configuration/src/main/java/otel/SdkMeterProviderConfig.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.sdk.metrics.SdkMeterProvider; 4 | import io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder; 5 | import io.opentelemetry.sdk.resources.Resource; 6 | import java.util.List; 7 | import java.util.Set; 8 | 9 | public class SdkMeterProviderConfig { 10 | public static SdkMeterProvider create(Resource resource) { 11 | SdkMeterProviderBuilder builder = 12 | SdkMeterProvider.builder() 13 | .setResource(resource) 14 | .registerMetricReader( 15 | MetricReaderConfig.periodicMetricReader( 16 | MetricExporterConfig.otlpHttpMetricExporter( 17 | "http://localhost:4318/v1/metrics"))); 18 | // Uncomment to optionally register metric reader with cardinality limits 19 | // builder.registerMetricReader( 20 | // MetricReaderConfig.periodicMetricReader( 21 | // MetricExporterConfig.otlpHttpMetricExporter("http://localhost:4318/v1/metrics")), 22 | // instrumentType -> 100); 23 | 24 | ViewConfig.dropMetricView(builder, "some.custom.metric"); 25 | ViewConfig.histogramBucketBoundariesView( 26 | builder, "http.server.request.duration", List.of(1.0, 5.0, 10.0)); 27 | ViewConfig.attributeFilterView( 28 | builder, "http.client.request.duration", Set.of("http.request.method")); 29 | ViewConfig.cardinalityLimitsView(builder, "http.server.active_requests", 100); 30 | return builder.build(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /doc-snippets/configuration/src/main/java/otel/SdkTracerProviderConfig.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.sdk.resources.Resource; 4 | import io.opentelemetry.sdk.trace.SdkTracerProvider; 5 | 6 | public class SdkTracerProviderConfig { 7 | public static SdkTracerProvider create(Resource resource) { 8 | return SdkTracerProvider.builder() 9 | .setResource(resource) 10 | .addSpanProcessor( 11 | SpanProcessorConfig.batchSpanProcessor( 12 | SpanExporterConfig.otlpHttpSpanExporter("http://localhost:4318/v1/spans"))) 13 | .setSampler(SamplerConfig.parentBasedSampler(SamplerConfig.traceIdRatioBased(.25))) 14 | .setSpanLimits(SpanLimitsConfig::spanLimits) 15 | .build(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /doc-snippets/configuration/src/main/java/otel/SpanExporterConfig.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.exporter.logging.LoggingSpanExporter; 4 | import io.opentelemetry.exporter.logging.otlp.OtlpJsonLoggingSpanExporter; 5 | import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter; 6 | import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter; 7 | import io.opentelemetry.sdk.trace.export.SpanExporter; 8 | import java.time.Duration; 9 | 10 | public class SpanExporterConfig { 11 | public static SpanExporter otlpHttpSpanExporter(String endpoint) { 12 | return OtlpHttpSpanExporter.builder() 13 | .setEndpoint(endpoint) 14 | .addHeader("api-key", "value") 15 | .setTimeout(Duration.ofSeconds(10)) 16 | .build(); 17 | } 18 | 19 | public static SpanExporter otlpGrpcSpanExporter(String endpoint) { 20 | return OtlpGrpcSpanExporter.builder() 21 | .setEndpoint(endpoint) 22 | .addHeader("api-key", "value") 23 | .setTimeout(Duration.ofSeconds(10)) 24 | .build(); 25 | } 26 | 27 | public static SpanExporter logginSpanExporter() { 28 | return LoggingSpanExporter.create(); 29 | } 30 | 31 | public static SpanExporter otlpJsonLoggingSpanExporter() { 32 | return OtlpJsonLoggingSpanExporter.create(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /doc-snippets/configuration/src/main/java/otel/SpanLimitsConfig.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.sdk.trace.SpanLimits; 4 | 5 | public class SpanLimitsConfig { 6 | public static SpanLimits spanLimits() { 7 | return SpanLimits.builder() 8 | .setMaxNumberOfAttributes(128) 9 | .setMaxAttributeValueLength(1024) 10 | .setMaxNumberOfLinks(128) 11 | .setMaxNumberOfAttributesPerLink(128) 12 | .setMaxNumberOfEvents(128) 13 | .setMaxNumberOfAttributesPerEvent(128) 14 | .build(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /doc-snippets/configuration/src/main/java/otel/SpanProcessorConfig.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.sdk.trace.SpanProcessor; 4 | import io.opentelemetry.sdk.trace.export.BatchSpanProcessor; 5 | import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; 6 | import io.opentelemetry.sdk.trace.export.SpanExporter; 7 | import java.time.Duration; 8 | 9 | public class SpanProcessorConfig { 10 | public static SpanProcessor batchSpanProcessor(SpanExporter spanExporter) { 11 | return BatchSpanProcessor.builder(spanExporter) 12 | .setMaxQueueSize(2048) 13 | .setExporterTimeout(Duration.ofSeconds(30)) 14 | .setScheduleDelay(Duration.ofSeconds(5)) 15 | .build(); 16 | } 17 | 18 | public static SpanProcessor simpleSpanProcessor(SpanExporter spanExporter) { 19 | return SimpleSpanProcessor.builder(spanExporter).build(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /doc-snippets/configuration/src/main/java/otel/ViewConfig.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.sdk.metrics.Aggregation; 4 | import io.opentelemetry.sdk.metrics.InstrumentSelector; 5 | import io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder; 6 | import io.opentelemetry.sdk.metrics.View; 7 | import java.util.List; 8 | import java.util.Set; 9 | 10 | public class ViewConfig { 11 | public static SdkMeterProviderBuilder dropMetricView( 12 | SdkMeterProviderBuilder builder, String metricName) { 13 | return builder.registerView( 14 | InstrumentSelector.builder().setName(metricName).build(), 15 | View.builder().setAggregation(Aggregation.drop()).build()); 16 | } 17 | 18 | public static SdkMeterProviderBuilder histogramBucketBoundariesView( 19 | SdkMeterProviderBuilder builder, String metricName, List bucketBoundaries) { 20 | return builder.registerView( 21 | InstrumentSelector.builder().setName(metricName).build(), 22 | View.builder() 23 | .setAggregation(Aggregation.explicitBucketHistogram(bucketBoundaries)) 24 | .build()); 25 | } 26 | 27 | public static SdkMeterProviderBuilder attributeFilterView( 28 | SdkMeterProviderBuilder builder, String metricName, Set keysToRetain) { 29 | return builder.registerView( 30 | InstrumentSelector.builder().setName(metricName).build(), 31 | View.builder().setAttributeFilter(keysToRetain).build()); 32 | } 33 | 34 | public static SdkMeterProviderBuilder cardinalityLimitsView( 35 | SdkMeterProviderBuilder builder, String metricName, int cardinalityLimit) { 36 | return builder.registerView( 37 | InstrumentSelector.builder().setName(metricName).build(), 38 | View.builder().setCardinalityLimit(cardinalityLimit).build()); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /doc-snippets/exporters/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.springframework.boot.gradle.plugin.SpringBootPlugin 2 | 3 | plugins { 4 | id("java") 5 | id("org.springframework.boot") version "3.5.0" 6 | } 7 | 8 | val moduleName by extra { "io.opentelemetry.examples.docs.exporters" } 9 | 10 | dependencies { 11 | implementation(platform(SpringBootPlugin.BOM_COORDINATES)) 12 | implementation(platform("io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom:2.16.0")) 13 | 14 | implementation("org.springframework.boot:spring-boot-starter-web") 15 | implementation("io.opentelemetry:opentelemetry-exporter-otlp") 16 | implementation("io.opentelemetry:opentelemetry-sdk") 17 | implementation("io.opentelemetry:opentelemetry-exporter-prometheus") 18 | implementation("io.opentelemetry:opentelemetry-exporter-zipkin") 19 | implementation("io.opentelemetry.semconv:opentelemetry-semconv") 20 | } 21 | -------------------------------------------------------------------------------- /doc-snippets/exporters/src/main/java/otel/BatchExporter.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.sdk.logs.SdkLoggerProvider; 4 | import io.opentelemetry.sdk.logs.export.BatchLogRecordProcessor; 5 | import io.opentelemetry.sdk.logs.export.LogRecordExporter; 6 | import io.opentelemetry.sdk.resources.Resource; 7 | import io.opentelemetry.sdk.trace.SdkTracerProvider; 8 | import io.opentelemetry.sdk.trace.export.BatchSpanProcessor; 9 | import io.opentelemetry.sdk.trace.export.SpanExporter; 10 | 11 | public class BatchExporter { 12 | public static void create( 13 | Resource resource, SpanExporter spanExporter, LogRecordExporter logExporter) { 14 | SdkTracerProvider sdkTracerProvider = 15 | SdkTracerProvider.builder() 16 | .addSpanProcessor(BatchSpanProcessor.builder(spanExporter).build()) 17 | .setResource(resource) 18 | .build(); 19 | 20 | SdkLoggerProvider sdkLoggerProvider = 21 | SdkLoggerProvider.builder() 22 | .addLogRecordProcessor(BatchLogRecordProcessor.builder(logExporter).build()) 23 | .setResource(resource) 24 | .build(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /doc-snippets/exporters/src/main/java/otel/PrometheusExporter.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.exporter.prometheus.PrometheusHttpServer; 4 | import io.opentelemetry.sdk.metrics.SdkMeterProvider; 5 | import io.opentelemetry.sdk.resources.Resource; 6 | 7 | public class PrometheusExporter { 8 | public static SdkMeterProvider create(Resource resource) { 9 | int prometheusPort = 9464; 10 | SdkMeterProvider sdkMeterProvider = 11 | SdkMeterProvider.builder() 12 | .registerMetricReader(PrometheusHttpServer.builder().setPort(prometheusPort).build()) 13 | .setResource(resource) 14 | .build(); 15 | 16 | return sdkMeterProvider; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /doc-snippets/exporters/src/main/java/otel/SimpleExporter.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.sdk.logs.SdkLoggerProvider; 4 | import io.opentelemetry.sdk.logs.export.LogRecordExporter; 5 | import io.opentelemetry.sdk.logs.export.SimpleLogRecordProcessor; 6 | import io.opentelemetry.sdk.resources.Resource; 7 | import io.opentelemetry.sdk.trace.SdkTracerProvider; 8 | import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; 9 | import io.opentelemetry.sdk.trace.export.SpanExporter; 10 | 11 | public class SimpleExporter { 12 | public static void create( 13 | Resource resource, SpanExporter spanExporter, LogRecordExporter logExporter) { 14 | SdkTracerProvider sdkTracerProvider = 15 | SdkTracerProvider.builder() 16 | .addSpanProcessor(SimpleSpanProcessor.builder(spanExporter).build()) 17 | .setResource(resource) 18 | .build(); 19 | 20 | SdkLoggerProvider sdkLoggerProvider = 21 | SdkLoggerProvider.builder() 22 | .addLogRecordProcessor(SimpleLogRecordProcessor.create(logExporter)) 23 | .setResource(resource) 24 | .build(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /doc-snippets/exporters/src/main/java/otel/ZipkinExporter.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.exporter.zipkin.ZipkinSpanExporter; 4 | import io.opentelemetry.sdk.resources.Resource; 5 | import io.opentelemetry.sdk.trace.SdkTracerProvider; 6 | import io.opentelemetry.sdk.trace.export.BatchSpanProcessor; 7 | 8 | public class ZipkinExporter { 9 | public static SdkTracerProvider create(Resource resource) { 10 | SdkTracerProvider sdkTracerProvider = 11 | SdkTracerProvider.builder() 12 | .addSpanProcessor( 13 | BatchSpanProcessor.builder( 14 | ZipkinSpanExporter.builder() 15 | .setEndpoint("http://localhost:9411/api/v2/spans") 16 | .build()) 17 | .build()) 18 | .setResource(resource) 19 | .build(); 20 | 21 | return sdkTracerProvider; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /doc-snippets/getting-started/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.springframework.boot.gradle.plugin.SpringBootPlugin 2 | 3 | plugins { 4 | id("java") 5 | id("org.springframework.boot") version "3.5.0" 6 | } 7 | 8 | val moduleName by extra { "io.opentelemetry.examples.docs.getting-started" } 9 | 10 | dependencies { 11 | implementation(platform(SpringBootPlugin.BOM_COORDINATES)) 12 | implementation(platform("io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom:2.16.0")) 13 | 14 | implementation("org.springframework.boot:spring-boot-starter-web") 15 | } 16 | -------------------------------------------------------------------------------- /doc-snippets/getting-started/src/main/java/otel/DiceApplication.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import org.springframework.boot.Banner; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | 7 | @SpringBootApplication 8 | public class DiceApplication { 9 | public static void main(String[] args) { 10 | SpringApplication app = new SpringApplication(DiceApplication.class); 11 | app.setBannerMode(Banner.Mode.OFF); 12 | app.run(args); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /doc-snippets/getting-started/src/main/java/otel/RollController.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import java.util.Optional; 4 | import java.util.concurrent.ThreadLocalRandom; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.RequestParam; 9 | import org.springframework.web.bind.annotation.RestController; 10 | 11 | @RestController 12 | public class RollController { 13 | private static final Logger logger = LoggerFactory.getLogger(RollController.class); 14 | 15 | @GetMapping("/rolldice") 16 | public String index(@RequestParam("player") Optional player) { 17 | int result = this.getRandomNumber(1, 6); 18 | if (player.isPresent()) { 19 | logger.info("{} is rolling the dice: {}", player.get(), result); 20 | } else { 21 | logger.info("Anonymous player is rolling the dice: {}", result); 22 | } 23 | return Integer.toString(result); 24 | } 25 | 26 | public int getRandomNumber(int min, int max) { 27 | return ThreadLocalRandom.current().nextInt(min, max + 1); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /doc-snippets/spring-starter/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.springframework.boot.gradle.plugin.SpringBootPlugin 2 | 3 | plugins { 4 | id("java") 5 | id("org.springframework.boot") version "3.5.0" 6 | } 7 | 8 | val moduleName by extra { "io.opentelemetry.examples.docs.spring-starter" } 9 | 10 | dependencies { 11 | implementation(platform(SpringBootPlugin.BOM_COORDINATES)) 12 | implementation(platform("io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom:2.16.0")) 13 | 14 | implementation("org.springframework.boot:spring-boot-starter-web") 15 | implementation("org.springframework.boot:spring-boot-starter-webflux") 16 | implementation("io.opentelemetry.instrumentation:opentelemetry-spring-boot-starter") 17 | implementation("io.opentelemetry.contrib:opentelemetry-samplers:1.46.0-alpha") 18 | } 19 | 20 | springBoot { 21 | mainClass = "otel.Application" 22 | } 23 | -------------------------------------------------------------------------------- /doc-snippets/spring-starter/src/main/java/otel/Application.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import org.springframework.boot.autoconfigure.SpringBootApplication; 4 | 5 | @SpringBootApplication 6 | public class Application {} 7 | -------------------------------------------------------------------------------- /doc-snippets/spring-starter/src/main/java/otel/CustomAuth.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter; 4 | import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider; 5 | import java.util.Collections; 6 | import java.util.Map; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | 10 | @Configuration 11 | public class CustomAuth { 12 | @Bean 13 | public AutoConfigurationCustomizerProvider otelCustomizer() { 14 | return p -> 15 | p.addSpanExporterCustomizer( 16 | (exporter, config) -> { 17 | if (exporter instanceof OtlpHttpSpanExporter) { 18 | return ((OtlpHttpSpanExporter) exporter) 19 | .toBuilder().setHeaders(this::headers).build(); 20 | } 21 | return exporter; 22 | }); 23 | } 24 | 25 | private Map headers() { 26 | return Collections.singletonMap("Authorization", "Bearer " + refreshToken()); 27 | } 28 | 29 | private String refreshToken() { 30 | // e.g. read the token from a kubernetes secret 31 | return "token"; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /doc-snippets/spring-starter/src/main/java/otel/FilterPaths.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.api.trace.SpanKind; 4 | import io.opentelemetry.contrib.sampler.RuleBasedRoutingSampler; 5 | import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider; 6 | import io.opentelemetry.semconv.UrlAttributes; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | 10 | @Configuration 11 | public class FilterPaths { 12 | 13 | @Bean 14 | public AutoConfigurationCustomizerProvider otelCustomizer() { 15 | return p -> 16 | p.addSamplerCustomizer( 17 | (fallback, config) -> 18 | RuleBasedRoutingSampler.builder(SpanKind.SERVER, fallback) 19 | .drop(UrlAttributes.URL_PATH, "^/actuator") 20 | .build()); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /doc-snippets/spring-starter/src/main/java/otel/RestClientConfig.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.web.client.RestClient; 6 | 7 | @Configuration 8 | public class RestClientConfig { 9 | 10 | @Bean 11 | public RestClient restClient() { 12 | return RestClient.create(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /doc-snippets/spring-starter/src/main/java/otel/RestClientController.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import org.springframework.web.bind.annotation.RestController; 4 | import org.springframework.web.client.RestClient; 5 | 6 | @RestController 7 | public class RestClientController { 8 | 9 | private final RestClient restClient; 10 | 11 | public RestClientController(RestClient.Builder restClientBuilder) { 12 | restClient = restClientBuilder.baseUrl("http://localhost:8080").build(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /doc-snippets/spring-starter/src/main/java/otel/RestTemplateConfig.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.web.client.RestTemplate; 6 | 7 | @Configuration 8 | public class RestTemplateConfig { 9 | 10 | @Bean 11 | public RestTemplate restTemplate() { 12 | return new RestTemplate(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /doc-snippets/spring-starter/src/main/java/otel/RestTemplateController.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import org.springframework.boot.web.client.RestTemplateBuilder; 4 | import org.springframework.web.bind.annotation.RestController; 5 | import org.springframework.web.client.RestTemplate; 6 | 7 | @RestController 8 | public class RestTemplateController { 9 | 10 | private final RestTemplate restTemplate; 11 | 12 | public RestTemplateController(RestTemplateBuilder restTemplateBuilder) { 13 | restTemplate = restTemplateBuilder.rootUri("http://localhost:8080").build(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /doc-snippets/spring-starter/src/main/java/otel/TracedClass.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import io.opentelemetry.api.trace.Span; 4 | import io.opentelemetry.api.trace.SpanKind; 5 | import io.opentelemetry.instrumentation.annotations.SpanAttribute; 6 | import io.opentelemetry.instrumentation.annotations.WithSpan; 7 | import org.springframework.stereotype.Component; 8 | 9 | /** Test WithSpan */ 10 | @Component 11 | public class TracedClass { 12 | 13 | @WithSpan 14 | public void tracedMethod() {} 15 | 16 | @WithSpan(value = "span name") 17 | public void tracedMethodWithName() { 18 | Span currentSpan = Span.current(); 19 | currentSpan.addEvent("ADD EVENT TO tracedMethodWithName SPAN"); 20 | currentSpan.setAttribute("isTestAttribute", true); 21 | } 22 | 23 | @WithSpan(kind = SpanKind.CLIENT) 24 | public void tracedClientSpan() {} 25 | 26 | public void tracedMethodWithAttribute(@SpanAttribute("attributeName") String parameter) {} 27 | } 28 | -------------------------------------------------------------------------------- /doc-snippets/spring-starter/src/main/java/otel/WebClientConfig.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.web.reactive.function.client.WebClient; 6 | 7 | @Configuration 8 | public class WebClientConfig { 9 | 10 | @Bean 11 | public WebClient webClient() { 12 | return WebClient.create(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /doc-snippets/spring-starter/src/main/java/otel/WebClientController.java: -------------------------------------------------------------------------------- 1 | package otel; 2 | 3 | import org.springframework.web.bind.annotation.RestController; 4 | import org.springframework.web.reactive.function.client.WebClient; 5 | 6 | @RestController 7 | public class WebClientController { 8 | 9 | private final WebClient webClient; 10 | 11 | public WebClientController(WebClient.Builder webClientBuilder) { 12 | webClient = webClientBuilder.baseUrl("http://localhost:8080").build(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.parallel=true 2 | org.gradle.caching=true 3 | 4 | org.gradle.priority=low 5 | 6 | # Gradle default is 256m which causes issues with our build - https://docs.gradle.org/current/userguide/build_environment.html#sec:configuring_jvm_memory 7 | # Also workaround https://github.com/diffplug/spotless/issues/834 8 | org.gradle.jvmargs=-XX:MaxMetaspaceSize=512m \ 9 | --add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \ 10 | --add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED \ 11 | --add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED \ 12 | --add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED \ 13 | --add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED \ -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-telemetry/opentelemetry-java-examples/a37e6a837adf34bc3390d8fb26e81a4a70bbe109/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionSha256Sum=7197a12f450794931532469d4ff21a59ea2c1cd59a3ec3f89c035c3c420a6999 4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip 5 | networkTimeout=10000 6 | validateDistributionUrl=true 7 | zipStoreBase=GRADLE_USER_HOME 8 | zipStorePath=wrapper/dists 9 | -------------------------------------------------------------------------------- /grpc/README.md: -------------------------------------------------------------------------------- 1 | # GRPC Example 2 | 3 | **Note:** This is an advanced scenario useful for people who want to *manually* instrument their own code. 4 | (If you're using the [java agent](https://github.com/open-telemetry/opentelemetry-java-instrumentation), you get this instrumentation "out-of-the-box" and this isn't necessary.) 5 | 6 | This is a simple example that demonstrates how to use the OpenTelemetry SDK 7 | to *manually* instrument a simple GRPC based Client/Server application. 8 | This example utilizes the [opentelemetry-grpc-1.6](https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/instrumentation/grpc-1.6/library#library-instrumentation-for-grpc-160) 9 | to instrument both the GRPC client and server. 10 | 11 | # How to run 12 | 13 | ## Prerequisites 14 | * Be on the grpc project root folder 15 | ```shell script 16 | cd grpc/ 17 | ``` 18 | 19 | ## 1 - Compile 20 | ```shell script 21 | ../gradlew shadowJar 22 | ``` 23 | 24 | ## 2 - Start the Server 25 | ```shell script 26 | java -cp ./build/libs/opentelemetry-examples-grpc-0.1.0-SNAPSHOT-all.jar io.opentelemetry.examples.grpc.HelloWorldServer 27 | ``` 28 | 29 | ## 3 - Start the Client 30 | ```shell script 31 | java -cp ./build/libs/opentelemetry-examples-grpc-0.1.0-SNAPSHOT-all.jar io.opentelemetry.examples.grpc.HelloWorldClient 32 | ``` 33 | 34 | ## Result 35 | ![trace_result.png](trace_result.png) 36 | ![client_trace.png](client_trace.png) 37 | ![server_trace.png](server_trace.png) -------------------------------------------------------------------------------- /grpc/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import com.google.protobuf.gradle.* 2 | 3 | plugins { 4 | id("java") 5 | id ("com.google.protobuf") 6 | id ("idea") 7 | } 8 | 9 | description = "OpenTelemetry Examples for GRPC" 10 | val moduleName by extra { "io.opentelemetry.examples.grpc" } 11 | 12 | java { 13 | toolchain { 14 | languageVersion.set(JavaLanguageVersion.of(8)) 15 | } 16 | } 17 | 18 | var grpcVersion = "1.73.0" // CURRENT_GRPC_VERSION 19 | var protobufVersion = "4.31.1" 20 | var protocVersion = protobufVersion 21 | 22 | dependencies { 23 | runtimeOnly ("io.grpc:grpc-netty-shaded:${grpcVersion}") 24 | implementation ("io.grpc:grpc-protobuf:${grpcVersion}") 25 | implementation ("io.grpc:grpc-services:${grpcVersion}") 26 | implementation ("io.grpc:grpc-stub:${grpcVersion}") 27 | implementation ("com.google.protobuf:protobuf-java-util:${protobufVersion}") 28 | implementation ("io.opentelemetry.instrumentation:opentelemetry-grpc-1.6:2.16.0-alpha") 29 | implementation ("com.google.guava:guava:33.4.8-jre") 30 | 31 | implementation("io.opentelemetry:opentelemetry-api") 32 | implementation("io.opentelemetry:opentelemetry-sdk") 33 | implementation("io.opentelemetry:opentelemetry-exporter-zipkin") 34 | implementation("io.opentelemetry.instrumentation:opentelemetry-grpc-1.6") 35 | 36 | //alpha modules 37 | implementation("io.opentelemetry.semconv:opentelemetry-semconv") 38 | } 39 | 40 | protobuf { 41 | protoc { 42 | // The artifact spec for the Protobuf Compiler 43 | artifact = "com.google.protobuf:protoc:${protobufVersion}" 44 | } 45 | plugins { 46 | id("grpc") { 47 | artifact = "io.grpc:protoc-gen-grpc-java:${grpcVersion}" 48 | } 49 | } 50 | generateProtoTasks { 51 | all().configureEach { 52 | plugins { 53 | id("grpc") 54 | } 55 | } 56 | } 57 | } 58 | 59 | tasks.shadowJar { 60 | mergeServiceFiles() 61 | } 62 | -------------------------------------------------------------------------------- /grpc/client_trace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-telemetry/opentelemetry-java-examples/a37e6a837adf34bc3390d8fb26e81a4a70bbe109/grpc/client_trace.png -------------------------------------------------------------------------------- /grpc/server_trace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-telemetry/opentelemetry-java-examples/a37e6a837adf34bc3390d8fb26e81a4a70bbe109/grpc/server_trace.png -------------------------------------------------------------------------------- /grpc/src/main/java/io/opentelemetry/examples/grpc/ExampleConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | package io.opentelemetry.examples.grpc; 7 | 8 | import io.opentelemetry.api.OpenTelemetry; 9 | import io.opentelemetry.api.common.Attributes; 10 | import io.opentelemetry.exporter.zipkin.ZipkinSpanExporter; 11 | import io.opentelemetry.sdk.OpenTelemetrySdk; 12 | import io.opentelemetry.sdk.resources.Resource; 13 | import io.opentelemetry.sdk.trace.SdkTracerProvider; 14 | import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; 15 | import io.opentelemetry.semconv.ServiceAttributes; 16 | 17 | public final class ExampleConfiguration { 18 | 19 | // Name of the service 20 | private static final String SERVICE_NAME = "myExampleService"; 21 | 22 | /** Adds a SimpleSpanProcessor initialized with ZipkinSpanExporter to the TracerSdkProvider */ 23 | static OpenTelemetry initializeOpenTelemetry(String ip, int port) { 24 | String endpoint = String.format("http://%s:%s/api/v2/spans", ip, port); 25 | ZipkinSpanExporter zipkinExporter = ZipkinSpanExporter.builder().setEndpoint(endpoint).build(); 26 | 27 | Resource serviceNameResource = 28 | Resource.create(Attributes.of(ServiceAttributes.SERVICE_NAME, SERVICE_NAME)); 29 | 30 | // Set to process the spans by the Zipkin Exporter 31 | SdkTracerProvider tracerProvider = 32 | SdkTracerProvider.builder() 33 | .addSpanProcessor(SimpleSpanProcessor.create(zipkinExporter)) 34 | .setResource(Resource.getDefault().merge(serviceNameResource)) 35 | .build(); 36 | OpenTelemetrySdk openTelemetry = 37 | OpenTelemetrySdk.builder().setTracerProvider(tracerProvider).buildAndRegisterGlobal(); 38 | 39 | // add a shutdown hook to shut down the SDK 40 | Runtime.getRuntime().addShutdownHook(new Thread(tracerProvider::close)); 41 | 42 | // return the configured instance so it can be used for instrumentation. 43 | return openTelemetry; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /grpc/src/main/proto/helloworld.proto: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | syntax = "proto3"; 6 | 7 | option java_multiple_files = true; 8 | option java_package = "io.opentelemetry.examples.grpc"; 9 | option java_outer_classname = "HelloWorldProto"; 10 | 11 | package helloworld; 12 | 13 | // The greeting service definition. 14 | service Greeter { 15 | // Sends a greeting 16 | rpc SayHello (HelloRequest) returns (HelloReply) {} 17 | } 18 | 19 | // The request message containing the user's name. 20 | message HelloRequest { 21 | string name = 1; 22 | } 23 | 24 | // The response message containing the greetings 25 | message HelloReply { 26 | string message = 1; 27 | } 28 | -------------------------------------------------------------------------------- /grpc/trace_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-telemetry/opentelemetry-java-examples/a37e6a837adf34bc3390d8fb26e81a4a70bbe109/grpc/trace_result.png -------------------------------------------------------------------------------- /http/README.md: -------------------------------------------------------------------------------- 1 | # HTTP Example 2 | 3 | **Note:** This is an advanced scenario useful for people that want to *manually* instrument their own code. 4 | 5 | This is a simple example that demonstrates how to use the OpenTelemetry SDK 6 | to *manually* instrument a simple HTTP based Client/Server application. 7 | The example creates the **Root Span** on the client and sends the context 8 | over the HTTP request. On the server side, the example shows how to extract the context 9 | and create a **Child Span** with attached a **Span Event**. 10 | 11 | # How to run 12 | 13 | ## Prerequisites 14 | * Java 1.8.231 15 | * Be on the project root folder 16 | 17 | ## 1 - Compile 18 | ```shell script 19 | ../gradlew shadowJar 20 | ``` 21 | 22 | ## 2 - Start the Server 23 | ```shell script 24 | java -cp ./build/libs/opentelemetry-examples-http-0.1.0-SNAPSHOT-all.jar io.opentelemetry.example.http.HttpServer 25 | ``` 26 | 27 | ## 3 - Start the Client 28 | ```shell script 29 | java -cp ./build/libs/opentelemetry-examples-http-0.1.0-SNAPSHOT-all.jar io.opentelemetry.example.http.HttpClient 30 | ``` 31 | -------------------------------------------------------------------------------- /http/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("java") 3 | } 4 | 5 | description = "OpenTelemetry Examples for HTTP" 6 | val moduleName by extra { "io.opentelemetry.examples.http" } 7 | 8 | java { 9 | toolchain { 10 | languageVersion.set(JavaLanguageVersion.of(8)) 11 | } 12 | } 13 | 14 | dependencies { 15 | implementation("io.opentelemetry:opentelemetry-api") 16 | implementation("io.opentelemetry:opentelemetry-sdk") 17 | implementation("io.opentelemetry:opentelemetry-exporter-logging") 18 | 19 | //alpha modules 20 | implementation("io.opentelemetry.semconv:opentelemetry-semconv") 21 | implementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure") 22 | implementation("io.opentelemetry:opentelemetry-api-incubator") 23 | } 24 | -------------------------------------------------------------------------------- /http/src/main/java/io/opentelemetry/example/http/ExampleConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | package io.opentelemetry.example.http; 7 | 8 | import io.opentelemetry.api.OpenTelemetry; 9 | import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; 10 | import io.opentelemetry.context.propagation.ContextPropagators; 11 | import io.opentelemetry.exporter.logging.LoggingSpanExporter; 12 | import io.opentelemetry.sdk.OpenTelemetrySdk; 13 | import io.opentelemetry.sdk.trace.SdkTracerProvider; 14 | import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; 15 | 16 | /** 17 | * All SDK management takes place here, away from the instrumentation code, which should only access 18 | * the OpenTelemetry APIs. 19 | */ 20 | class ExampleConfiguration { 21 | 22 | /** 23 | * Initializes the OpenTelemetry SDK with a logging span exporter and the W3C Trace Context 24 | * propagator. 25 | * 26 | * @return A ready-to-use {@link OpenTelemetry} instance. 27 | */ 28 | static OpenTelemetry initOpenTelemetry() { 29 | SdkTracerProvider sdkTracerProvider = 30 | SdkTracerProvider.builder() 31 | .addSpanProcessor(SimpleSpanProcessor.create(new LoggingSpanExporter())) 32 | .build(); 33 | 34 | OpenTelemetrySdk sdk = 35 | OpenTelemetrySdk.builder() 36 | .setTracerProvider(sdkTracerProvider) 37 | .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance())) 38 | .build(); 39 | 40 | Runtime.getRuntime().addShutdownHook(new Thread(sdkTracerProvider::close)); 41 | return sdk; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /jaeger/README.md: -------------------------------------------------------------------------------- 1 | # Jaeger Example 2 | 3 | This is a simple example that demonstrates how to use the OpenTelemetry SDK 4 | to instrument a simple application and export to a Jaeger backend. 5 | 6 | # How to run 7 | 8 | ## Prerequisites 9 | * Java 1.8+ 10 | * Docker 19.03 11 | * Jaeger 1.16 - [Link][jaeger] 12 | 13 | 14 | ## 1 - Compile 15 | ```shell script 16 | ../gradlew shadowJar 17 | ``` 18 | ## 2 - Run Jaeger 19 | 20 | ```shell script 21 | docker run --rm -it --name jaeger\ 22 | -e COLLECTOR_OTLP_ENABLED=true \ 23 | -p 4317:4317 \ 24 | -p 16686:16686 \ 25 | jaegertracing/all-in-one:1.39 26 | ``` 27 | 28 | 29 | ## 3 - Start the Application 30 | ```shell script 31 | java -cp build/libs/opentelemetry-examples-jaeger-0.1.0-SNAPSHOT-all.jar io.opentelemetry.example.jaeger.JaegerExample http://localhost:4317 32 | ``` 33 | ## 4 - Open the Jaeger UI 34 | 35 | Navigate to http://localhost:16686 36 | 37 | [jaeger]: https://www.jaegertracing.io/docs/1.16/getting-started/ 38 | -------------------------------------------------------------------------------- /jaeger/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("java") 3 | } 4 | 5 | description = "OpenTelemetry Examples for Jaeger Backend" 6 | val moduleName by extra { "io.opentelemetry.examples.jaeger" } 7 | 8 | java { 9 | toolchain { 10 | languageVersion.set(JavaLanguageVersion.of(8)) 11 | } 12 | } 13 | 14 | dependencies { 15 | implementation("io.opentelemetry:opentelemetry-api") 16 | implementation("io.opentelemetry:opentelemetry-sdk") 17 | implementation("io.opentelemetry:opentelemetry-exporter-otlp") 18 | 19 | //alpha module 20 | implementation("io.opentelemetry.semconv:opentelemetry-semconv") 21 | } 22 | -------------------------------------------------------------------------------- /jaeger/src/main/java/io/opentelemetry/example/jaeger/ExampleConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | package io.opentelemetry.example.jaeger; 7 | 8 | import static io.opentelemetry.semconv.ServiceAttributes.SERVICE_NAME; 9 | 10 | import io.opentelemetry.api.OpenTelemetry; 11 | import io.opentelemetry.api.common.Attributes; 12 | import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter; 13 | import io.opentelemetry.sdk.OpenTelemetrySdk; 14 | import io.opentelemetry.sdk.resources.Resource; 15 | import io.opentelemetry.sdk.trace.SdkTracerProvider; 16 | import io.opentelemetry.sdk.trace.export.BatchSpanProcessor; 17 | import java.util.concurrent.TimeUnit; 18 | 19 | /** 20 | * All SDK management takes place here, away from the instrumentation code, which should only access 21 | * the OpenTelemetry APIs. 22 | */ 23 | class ExampleConfiguration { 24 | 25 | /** 26 | * Initialize an OpenTelemetry SDK with a {@link OtlpGrpcSpanExporter} and a {@link 27 | * BatchSpanProcessor}. 28 | * 29 | * @param jaegerEndpoint The endpoint of your Jaeger instance. 30 | * @return A ready-to-use {@link OpenTelemetry} instance. 31 | */ 32 | static OpenTelemetry initOpenTelemetry(String jaegerEndpoint) { 33 | // Export traces to Jaeger over OTLP 34 | OtlpGrpcSpanExporter jaegerOtlpExporter = 35 | OtlpGrpcSpanExporter.builder() 36 | .setEndpoint(jaegerEndpoint) 37 | .setTimeout(30, TimeUnit.SECONDS) 38 | .build(); 39 | 40 | Resource serviceNameResource = 41 | Resource.create(Attributes.of(SERVICE_NAME, "otel-jaeger-example")); 42 | 43 | // Set to process the spans by the Jaeger Exporter 44 | SdkTracerProvider tracerProvider = 45 | SdkTracerProvider.builder() 46 | .addSpanProcessor(BatchSpanProcessor.builder(jaegerOtlpExporter).build()) 47 | .setResource(Resource.getDefault().merge(serviceNameResource)) 48 | .build(); 49 | OpenTelemetrySdk openTelemetry = 50 | OpenTelemetrySdk.builder().setTracerProvider(tracerProvider).build(); 51 | 52 | // it's always a good idea to shut down the SDK cleanly at JVM exit. 53 | Runtime.getRuntime().addShutdownHook(new Thread(tracerProvider::close)); 54 | 55 | return openTelemetry; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /jaeger/src/main/java/io/opentelemetry/example/jaeger/JaegerExample.java: -------------------------------------------------------------------------------- 1 | package io.opentelemetry.example.jaeger; 2 | 3 | import io.opentelemetry.api.OpenTelemetry; 4 | import io.opentelemetry.api.trace.Span; 5 | import io.opentelemetry.api.trace.Tracer; 6 | 7 | public final class JaegerExample { 8 | 9 | private final Tracer tracer; 10 | 11 | public JaegerExample(OpenTelemetry openTelemetry) { 12 | tracer = openTelemetry.getTracer("io.opentelemetry.example.JaegerExample"); 13 | } 14 | 15 | private void myWonderfulUseCase() { 16 | // Generate a span 17 | Span span = this.tracer.spanBuilder("Start my wonderful use case").startSpan(); 18 | span.addEvent("Event 0"); 19 | // execute my use case - here we simulate a wait 20 | doWork(); 21 | span.addEvent("Event 1"); 22 | span.end(); 23 | } 24 | 25 | private void doWork() { 26 | try { 27 | Thread.sleep(1000); 28 | } catch (InterruptedException e) { 29 | // do the right thing here 30 | } 31 | } 32 | 33 | public static void main(String[] args) { 34 | // Parsing the input 35 | if (args.length < 1) { 36 | System.out.println("Missing [endpoint]"); 37 | System.exit(1); 38 | } 39 | String jaegerEndpoint = args[0]; 40 | 41 | // it is important to initialize your SDK as early as possible in your application's lifecycle 42 | OpenTelemetry openTelemetry = ExampleConfiguration.initOpenTelemetry(jaegerEndpoint); 43 | 44 | // Start the example 45 | JaegerExample example = new JaegerExample(openTelemetry); 46 | // generate a few sample spans 47 | for (int i = 0; i < 10; i++) { 48 | example.myWonderfulUseCase(); 49 | } 50 | 51 | System.out.println("Bye"); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /javaagent/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM eclipse-temurin:17-jre 2 | 3 | ADD build/libs/app.jar /app.jar 4 | ADD build/agent/opentelemetry-javaagent.jar /opentelemetry-javaagent.jar 5 | ADD build/agent/opentelemetry-javaagent-extension.jar /opentelemetry-javaagent-extension.jar 6 | 7 | ENTRYPOINT java -javaagent:/opentelemetry-javaagent.jar -Dotel.javaagent.extensions=/opentelemetry-javaagent-extension.jar -jar /app.jar 8 | -------------------------------------------------------------------------------- /javaagent/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.springframework.boot.gradle.plugin.SpringBootPlugin 2 | import org.springframework.boot.gradle.tasks.bundling.BootJar 3 | 4 | plugins { 5 | id("java") 6 | id("org.springframework.boot") version "3.5.0" 7 | } 8 | 9 | description = "OpenTelemetry Example for Java Agent" 10 | val moduleName by extra { "io.opentelemetry.examples.javagent" } 11 | 12 | java { 13 | toolchain { 14 | languageVersion.set(JavaLanguageVersion.of(17)) 15 | } 16 | } 17 | 18 | val agent = configurations.create("agent") 19 | val extension = configurations.create("extension") 20 | 21 | dependencies { 22 | implementation(platform(SpringBootPlugin.BOM_COORDINATES)) 23 | implementation("io.opentelemetry:opentelemetry-api") 24 | 25 | //spring modules 26 | implementation("org.springframework.boot:spring-boot-starter-web") 27 | implementation("org.springframework.boot:spring-boot-starter-actuator") 28 | 29 | agent("io.opentelemetry.javaagent:opentelemetry-javaagent:2.16.0") 30 | extension("io.opentelemetry.contrib:opentelemetry-samplers:1.46.0-alpha") { 31 | isTransitive = false 32 | } 33 | } 34 | 35 | val copyAgent = tasks.register("copyAgent") { 36 | from(agent.singleFile) 37 | into(layout.buildDirectory.dir("agent")) 38 | rename("opentelemetry-javaagent-.*\\.jar", "opentelemetry-javaagent.jar") 39 | } 40 | 41 | val copyExtension = tasks.register("copyExtension") { 42 | from(extension.singleFile) 43 | into(layout.buildDirectory.dir("agent")) 44 | rename(".*\\.jar", "opentelemetry-javaagent-extension.jar") 45 | } 46 | 47 | tasks.named("bootJar") { 48 | dependsOn(copyAgent) 49 | dependsOn(copyExtension) 50 | 51 | archiveFileName = "app.jar" 52 | } 53 | -------------------------------------------------------------------------------- /javaagent/collector-config.yaml: -------------------------------------------------------------------------------- 1 | receivers: 2 | otlp: 3 | protocols: 4 | http: 5 | endpoint: "0.0.0.0:4318" 6 | exporters: 7 | debug: 8 | verbosity: detailed 9 | service: 10 | pipelines: 11 | metrics: 12 | receivers: [otlp] 13 | exporters: [debug] 14 | traces: 15 | receivers: [otlp] 16 | exporters: [debug] 17 | logs: 18 | receivers: [otlp] 19 | exporters: [debug] 20 | -------------------------------------------------------------------------------- /javaagent/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | app: 4 | build: ./ 5 | environment: 6 | OTEL_SERVICE_NAME: "agent-example-app" 7 | OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: "http://collector:4318/v1/traces" 8 | OTEL_EXPORTER_OTLP_METRICS_ENDPOINT: "http://collector:4318/v1/metrics" 9 | OTEL_EXPORTER_OTLP_LOGS_ENDPOINT: "http://collector:4318/v1/logs" 10 | # Logs are disabled by default 11 | OTEL_LOGS_EXPORTER: "otlp" 12 | # Optional specify file configuration instead of using environment variable scheme 13 | # To use, call "export OTEL_EXPERIMENTAL_CONFIG_FILE=/sdk-config.yaml" before calling docker compose up 14 | OTEL_EXPERIMENTAL_CONFIG_FILE: 15 | ports: 16 | - "8080:8080" 17 | volumes: 18 | - ./sdk-config.yaml:/sdk-config.yaml 19 | depends_on: 20 | - collector 21 | collector: 22 | image: otel/opentelemetry-collector-contrib:0.127.0@sha256:e94cfd92357aa21f4101dda3c0c01f90e6f24115ba91b263c4d09fed7911ae68 23 | volumes: 24 | - ./collector-config.yaml:/collector-config.yaml 25 | command: ["--config=/collector-config.yaml"] 26 | expose: 27 | - "4318" 28 | ports: 29 | - "4318:4318" 30 | -------------------------------------------------------------------------------- /javaagent/src/main/java/io/opentelemetry/example/javagent/Application.java: -------------------------------------------------------------------------------- 1 | package io.opentelemetry.example.javagent; 2 | 3 | import io.opentelemetry.api.GlobalOpenTelemetry; 4 | import io.opentelemetry.api.OpenTelemetry; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | import org.springframework.context.annotation.Bean; 8 | 9 | @SpringBootApplication 10 | public class Application { 11 | 12 | public static void main(String[] args) { 13 | SpringApplication.run(Application.class, args); 14 | } 15 | 16 | @Bean 17 | public OpenTelemetry openTelemetry() { 18 | return GlobalOpenTelemetry.get(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /javaagent/src/main/java/io/opentelemetry/example/javagent/Controller.java: -------------------------------------------------------------------------------- 1 | package io.opentelemetry.example.javagent; 2 | 3 | import io.opentelemetry.api.OpenTelemetry; 4 | import io.opentelemetry.api.common.AttributeKey; 5 | import io.opentelemetry.api.common.Attributes; 6 | import io.opentelemetry.api.metrics.LongHistogram; 7 | import io.opentelemetry.api.metrics.Meter; 8 | import io.opentelemetry.api.trace.Span; 9 | import io.opentelemetry.api.trace.Tracer; 10 | import io.opentelemetry.context.Scope; 11 | import java.util.Random; 12 | import org.slf4j.Logger; 13 | import org.slf4j.LoggerFactory; 14 | import org.springframework.beans.factory.annotation.Autowired; 15 | import org.springframework.web.bind.annotation.GetMapping; 16 | import org.springframework.web.bind.annotation.RestController; 17 | 18 | @RestController 19 | public class Controller { 20 | 21 | private static final Logger LOGGER = LoggerFactory.getLogger(Controller.class); 22 | private final AttributeKey ATTR_METHOD = AttributeKey.stringKey("method"); 23 | 24 | private final Random random = new Random(); 25 | private final Tracer tracer; 26 | private final LongHistogram doWorkHistogram; 27 | 28 | @Autowired 29 | Controller(OpenTelemetry openTelemetry) { 30 | tracer = openTelemetry.getTracer(Application.class.getName()); 31 | Meter meter = openTelemetry.getMeter(Application.class.getName()); 32 | doWorkHistogram = meter.histogramBuilder("do-work").ofLongs().build(); 33 | } 34 | 35 | @GetMapping("/ping") 36 | public String ping() throws InterruptedException { 37 | int sleepTime = random.nextInt(200); 38 | doWork(sleepTime); 39 | doWorkHistogram.record(sleepTime, Attributes.of(ATTR_METHOD, "ping")); 40 | return "pong"; 41 | } 42 | 43 | private void doWork(int sleepTime) throws InterruptedException { 44 | Span span = tracer.spanBuilder("doWork").startSpan(); 45 | try (Scope ignored = span.makeCurrent()) { 46 | Thread.sleep(sleepTime); 47 | LOGGER.info("A sample log message!"); 48 | } finally { 49 | span.end(); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /kotlin-extension/README.md: -------------------------------------------------------------------------------- 1 | # Kotlin Extension examples 2 | 3 | This is a simple example that demonstrates how to use the Kotlin extension for attaching a Span context to a Kotlin 4 | coroutine. 5 | 6 | ## Prerequisites 7 | 8 | * Java 1.8 or higher 9 | 10 | ## Compile 11 | 12 | Compile with 13 | 14 | ```shell script 15 | ../gradlew shadowJar 16 | ``` 17 | 18 | ## Run 19 | 20 | The following commands are used to run the examples. 21 | 22 | ```shell script 23 | java -cp build/libs/kotlin-extension-0.1.0-SNAPSHOT-all.jar io.opentelemetry.example.kotlinextension.Application 24 | ``` 25 | -------------------------------------------------------------------------------- /kotlin-extension/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id ("org.jetbrains.kotlin.jvm") version "2.1.21" 3 | } 4 | 5 | description = "OpenTelemetry Example for Kotlin extensions" 6 | 7 | kotlin { 8 | compilerOptions { 9 | jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_1_8) 10 | } 11 | } 12 | 13 | java { 14 | toolchain { 15 | languageVersion.set(JavaLanguageVersion.of(8)) 16 | } 17 | } 18 | 19 | dependencies { 20 | implementation("io.opentelemetry:opentelemetry-extension-kotlin") 21 | implementation("io.opentelemetry:opentelemetry-sdk-testing") 22 | implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2") 23 | } -------------------------------------------------------------------------------- /kotlin-extension/src/main/kotlin/io/opentelemetry/example/kotlinextension/Application.kt: -------------------------------------------------------------------------------- 1 | package io.opentelemetry.example.kotlinextension 2 | 3 | import kotlinx.coroutines.runBlocking 4 | 5 | object Application { 6 | 7 | @JvmStatic 8 | fun main(vararg args: String) { 9 | runBlocking { 10 | CoroutineContextExample().run() 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /log-appender/README.md: -------------------------------------------------------------------------------- 1 | # OpenTelemetry Log Appender Example 2 | 3 | This example demonstrates an application configured to use the OpenTelemetry Log 4 | Appenders to bridge logs into the OpenTelemetry Log SDK, and export 5 | via [OTLP](https://opentelemetry.io/docs/reference/specification/protocol/otlp/). 6 | 7 | Details about the example: 8 | 9 | * The OpenTelemetry Log SDK is configured to export data to 10 | the [collector](https://opentelemetry.io/docs/collector/), which prints the 11 | logs to the console. 12 | * The application is configured with a variety of log solutions: 13 | * Log4j API [configured](./src/main/resources/log4j2.xml) to print logs to the 14 | console and 15 | the [OpenTelemetry Log4J Appender](https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/instrumentation/log4j/log4j-appender-2.17/library/README.md). 16 | * SLF4J API [configured with Logback](./src/main/resources/logback.xml) to 17 | print logs to the console and 18 | the [OpenTelemetry Logback Appender](https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/instrumentation/logback/logback-appender-1.0/library/README.md). 19 | * [JUL to SLF4J](./build.gradle.kts), which bridges JUL logs to the SLF4J API, and 20 | ultimately to Logback. 21 | * Demonstrates how trace context is propagated to logs when recorded within a 22 | span. 23 | 24 | ## Prerequisites 25 | 26 | * Java 1.8 27 | * Docker compose 28 | 29 | # How to run 30 | 31 | Run the collector via docker 32 | 33 | ```shell 34 | docker-compose up 35 | ``` 36 | 37 | In a separate shell, run the application 38 | 39 | ```shell 40 | ../gradlew run 41 | ``` 42 | 43 | Watch the collector logs to see exported log records 44 | -------------------------------------------------------------------------------- /log-appender/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("java") 3 | id("application") 4 | } 5 | 6 | description = "OpenTelemetry Log Appender Example" 7 | val moduleName by extra { "io.opentelemetry.examples.log-appender" } 8 | 9 | java { 10 | toolchain { 11 | // logback 1.4.x+ requires java 11 12 | languageVersion.set(JavaLanguageVersion.of(11)) 13 | } 14 | } 15 | 16 | dependencies { 17 | // Slf4J / logback 18 | implementation("org.slf4j:slf4j-api:2.0.17") 19 | implementation("ch.qos.logback:logback-core:1.5.18") 20 | implementation("ch.qos.logback:logback-classic:1.5.18") 21 | 22 | // JUL to SLF4J bridge 23 | implementation("org.slf4j:jul-to-slf4j:2.0.17") 24 | 25 | // Log4j 26 | implementation(platform("org.apache.logging.log4j:log4j-bom:2.24.3")) 27 | implementation("org.apache.logging.log4j:log4j-api") 28 | implementation("org.apache.logging.log4j:log4j-core") 29 | 30 | // OpenTelemetry core 31 | implementation("io.opentelemetry:opentelemetry-sdk") 32 | implementation("io.opentelemetry:opentelemetry-exporter-otlp") 33 | implementation("io.opentelemetry.semconv:opentelemetry-semconv") 34 | 35 | // OpenTelemetry log4j / logback appenders 36 | implementation("io.opentelemetry.instrumentation:opentelemetry-log4j-appender-2.17") 37 | implementation("io.opentelemetry.instrumentation:opentelemetry-logback-appender-1.0") 38 | } 39 | 40 | application { 41 | mainClass = "io.opentelemetry.example.logappender.Application" 42 | } 43 | -------------------------------------------------------------------------------- /log-appender/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | collector: 4 | image: otel/opentelemetry-collector-contrib:0.127.0@sha256:e94cfd92357aa21f4101dda3c0c01f90e6f24115ba91b263c4d09fed7911ae68 5 | volumes: 6 | - ./otel-config.yaml:/otel-config.yaml 7 | command: ["--config=/otel-config.yaml"] 8 | ports: 9 | - "4317:4317" 10 | -------------------------------------------------------------------------------- /log-appender/otel-config.yaml: -------------------------------------------------------------------------------- 1 | receivers: 2 | otlp: 3 | protocols: 4 | grpc: 5 | endpoint: collector:4317 6 | exporters: 7 | debug: 8 | verbosity: detailed 9 | service: 10 | pipelines: 11 | logs: 12 | receivers: [otlp] 13 | exporters: [debug] 14 | -------------------------------------------------------------------------------- /log-appender/src/main/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /log-appender/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | logback: %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg %kvp{DOUBLE}%n 7 | 8 | 9 | 10 | 12 | true 13 | true 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /logging-k8s-stdout-otlp-json/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM eclipse-temurin:21-jre 2 | 3 | WORKDIR /usr/src/app/ 4 | 5 | # renovate: datasource=github-releases depName=opentelemetry-java-instrumentation packageName=open-telemetry/opentelemetry-java-instrumentation 6 | ENV OPENTELEMETRY_JAVA_INSTRUMENTATION_VERSION=v2.16.0 7 | 8 | ADD build/libs/*SNAPSHOT.jar ./app.jar 9 | ADD --chmod=644 https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/download/$OPENTELEMETRY_JAVA_INSTRUMENTATION_VERSION/opentelemetry-javaagent.jar ./opentelemetry-javaagent.jar 10 | ENV JAVA_TOOL_OPTIONS=-javaagent:./opentelemetry-javaagent.jar 11 | 12 | EXPOSE 8080 13 | ENTRYPOINT [ "java", "-jar", "./app.jar" ] 14 | -------------------------------------------------------------------------------- /logging-k8s-stdout-otlp-json/README.md: -------------------------------------------------------------------------------- 1 | # Exporting Application logs using JSON logging in Kubernetes 2 | 3 | If you want to get logs from your Java application ingested into an 4 | OpenTelemetry-compatible logs backend, the easiest and recommended way is using 5 | an OpenTelemetry protocol (OTLP) exporter, 6 | which is explained in the [logging](../logging) example. 7 | 8 | However, some scenarios require logs 9 | to be output to files or stdout due to organizational or reliability needs. 10 | Refer to [Collecting OpenTelemetry-compliant Java logs from files](https://opentelemetry.io/blog/2024/collecting-otel-compliant-java-logs-from-files/) for more details. 11 | 12 | This example contains 13 | 14 | - a Java application that uses the experimental 15 | [experimental-otlp/stdout](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#in-development-exporter-selection) logs exporter 16 | - an OpenTelemetry collector configuration that uses the 17 | [OTLP/JSON connector](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/connector/otlpjsonconnector) to turn Pod logs into `OTLP` 18 | 19 | ## Architecture 20 | 21 | ![OTLP/JSON Architecture](otlpjson-architecture.png) 22 | 23 | The OpenTelemetry Collector pipeline: 24 | 25 | ![OpenTelemetry Collector Pipeline](otel-collector-otlpjson-pipeline.png) 26 | 27 | ## Getting Started 28 | 29 | The k8s directory contains the Kubernetes manifests to deploy the application and the collector. 30 | 31 | Ignore the `lgtm.yaml` file, which is only used for running locally with 32 | [LGTM](https://github.com/grafana/docker-otel-lgtm/) 33 | and automated testing using [OATs](https://github.com/grafana/oats). 34 | 35 | ## Running locally 36 | 37 | You can run the application locally using the following steps: 38 | 39 | 1. Run [k3d.sh](./k3d.sh) to start a local Kubernetes cluster with all the necessary components. 40 | 2. Generate traffic using [generate-traffic.sh](./generate-traffic.sh) 41 | 3. Log in to [http://localhost:3000](http://localhost:3000) 42 | 4. Go to "Explore" 43 | 5. Select "Loki" as data source to view the logs 44 | -------------------------------------------------------------------------------- /logging-k8s-stdout-otlp-json/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.springframework.boot.gradle.plugin.SpringBootPlugin 2 | import org.springframework.boot.gradle.tasks.bundling.BootJar 3 | 4 | plugins { 5 | id("java") 6 | id("org.springframework.boot") version "3.5.0" 7 | } 8 | 9 | description = "OpenTelemetry Example for Java Agent with Stdout logging" 10 | val moduleName by extra { "io.opentelemetry.examples.javagent.logging-k8s-stdout-otlp-json" } 11 | 12 | java { 13 | toolchain { 14 | languageVersion.set(JavaLanguageVersion.of(17)) 15 | } 16 | } 17 | 18 | dependencies { 19 | implementation(platform(SpringBootPlugin.BOM_COORDINATES)) 20 | 21 | implementation("org.springframework.boot:spring-boot-starter-web") 22 | implementation("org.springframework.boot:spring-boot-starter-actuator") 23 | } 24 | 25 | -------------------------------------------------------------------------------- /logging-k8s-stdout-otlp-json/generate-traffic.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | watch 'curl -s http://localhost:8080/rolldice' 4 | -------------------------------------------------------------------------------- /logging-k8s-stdout-otlp-json/k3d.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euo pipefail 4 | 5 | docker build -f Dockerfile -t "dice:1.1-SNAPSHOT" . 6 | k3d cluster create jsonlogging || k3d cluster start jsonlogging 7 | k3d image import -c jsonlogging dice:1.1-SNAPSHOT 8 | 9 | kubectl apply -f k8s/ 10 | 11 | kubectl wait --for=condition=ready pod -l app=dice 12 | kubectl wait --for=condition=ready --timeout=5m pod -l app=lgtm 13 | 14 | kubectl port-forward service/dice 8080:8080 & 15 | kubectl port-forward service/lgtm 3000:3000 & 16 | -------------------------------------------------------------------------------- /logging-k8s-stdout-otlp-json/k8s/collector-configmap.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: otel-collector-config 5 | data: 6 | otel-collector-config.yaml: |- 7 | receivers: 8 | otlp: 9 | protocols: 10 | grpc: 11 | endpoint: 0.0.0.0:4317 12 | http: 13 | endpoint: 0.0.0.0:4318 14 | filelog/otlp-json-logs: 15 | include: 16 | - /var/log/pods/*/*/*.log 17 | include_file_path: true 18 | operators: 19 | - id: container-parser 20 | type: container 21 | 22 | extensions: 23 | # needed if you use the docker-lgtm image 24 | health_check: 25 | endpoint: 0.0.0.0:13133 26 | path: "/ready" 27 | 28 | processors: 29 | batch: 30 | resourcedetection: 31 | detectors: [ "env", "system" ] 32 | override: false 33 | 34 | k8sattributes: 35 | # Config details in 36 | # https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/processor/k8sattributesprocessor 37 | connectors: 38 | otlpjson: 39 | 40 | exporters: 41 | otlphttp/metrics: 42 | endpoint: http://localhost:9090/api/v1/otlp 43 | otlphttp/traces: 44 | endpoint: http://localhost:4418 45 | otlphttp/logs: 46 | endpoint: http://localhost:3100/otlp 47 | debug/metrics: 48 | verbosity: detailed 49 | debug/traces: 50 | verbosity: detailed 51 | debug/logs: 52 | verbosity: detailed 53 | nop: 54 | 55 | service: 56 | extensions: [health_check] 57 | pipelines: 58 | traces: 59 | receivers: [ otlp ] 60 | processors: [ k8sattributes, resourcedetection, batch ] 61 | exporters: [ otlphttp/traces ] 62 | metrics: 63 | receivers: [ otlp ] 64 | processors: [ k8sattributes, resourcedetection, batch ] 65 | exporters: [ otlphttp/metrics ] 66 | logs/raw_otlpjson: 67 | receivers: [ filelog/otlp-json-logs ] 68 | # No need for processors before the otlpjson connector 69 | # Declare processors in the shared "logs" pipeline below 70 | processors: [ ] 71 | exporters: [ otlpjson ] 72 | logs/otlp: 73 | receivers: [ otlp, otlpjson ] 74 | processors: [ k8sattributes, resourcedetection, batch ] 75 | exporters: [ otlphttp/logs ] 76 | # exporters: [ otlphttp/logs, debug/logs ] # Uncomment this line to enable debug logging 77 | -------------------------------------------------------------------------------- /logging-k8s-stdout-otlp-json/k8s/dice.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: dice 5 | spec: 6 | selector: 7 | app: dice 8 | ports: 9 | - protocol: TCP 10 | port: 8080 11 | targetPort: 8080 12 | --- 13 | apiVersion: apps/v1 14 | kind: Deployment 15 | metadata: 16 | name: dice 17 | spec: 18 | replicas: 1 19 | selector: 20 | matchLabels: 21 | app: dice 22 | template: 23 | metadata: 24 | labels: 25 | app: dice 26 | spec: 27 | containers: 28 | - name: dice 29 | image: dice:1.1-SNAPSHOT 30 | imagePullPolicy: Never 31 | ports: 32 | - containerPort: 8080 33 | env: 34 | - name: OTEL_EXPORTER_OTLP_ENDPOINT 35 | value: "http://lgtm:4318" 36 | - name: OTEL_LOGS_EXPORTER 37 | value: "experimental-otlp/stdout" 38 | - name: OTEL_RESOURCE_ATTRIBUTES 39 | value: service.name=dice,service.namespace=shop,service.version=1.1,deployment.environment=staging 40 | - name: OTEL_INSTRUMENTATION_LOGBACK_APPENDER_EXPERIMENTAL_LOG_ATTRIBUTES 41 | value: "true" 42 | - name: OTEL_INSTRUMENTATION_LOGBACK_APPENDER_EXPERIMENTAL_CAPTURE_KEY_VALUE_PAIR_ATTRIBUTES 43 | value: "true" 44 | - name: OTEL_INSTRUMENTATION_LOGBACK_APPENDER_EXPERIMENTAL_CAPTURE_MDC_ATTRIBUTES 45 | value: "true" 46 | - name: SERVICE_NAME 47 | value: dice 48 | 49 | -------------------------------------------------------------------------------- /logging-k8s-stdout-otlp-json/k8s/lgtm.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: lgtm 5 | spec: 6 | selector: 7 | app: lgtm 8 | ports: 9 | - name: grafana 10 | protocol: TCP 11 | port: 3000 12 | targetPort: 3000 13 | - name: otel-grpc 14 | protocol: TCP 15 | port: 4317 16 | targetPort: 4317 17 | - name: otel-http 18 | protocol: TCP 19 | port: 4318 20 | targetPort: 4318 21 | - name: prometheus # needed for automated tests 22 | protocol: TCP 23 | port: 9090 24 | targetPort: 9090 25 | - name: loki # needed for automated tests 26 | protocol: TCP 27 | port: 3100 28 | targetPort: 3100 29 | - name: tempo # needed for automated tests 30 | protocol: TCP 31 | port: 3200 32 | targetPort: 3200 33 | --- 34 | apiVersion: apps/v1 35 | kind: Deployment 36 | metadata: 37 | name: lgtm 38 | spec: 39 | replicas: 1 40 | selector: 41 | matchLabels: 42 | app: lgtm 43 | template: 44 | metadata: 45 | labels: 46 | app: lgtm 47 | spec: 48 | containers: 49 | - name: lgtm 50 | image: grafana/otel-lgtm:0.11.4@sha256:518d264f8f57afd9f0f73b9b85a4e6440afec0254ea1d78a8333330070d40175 51 | ports: 52 | - containerPort: 3000 53 | - containerPort: 4317 54 | - containerPort: 4318 55 | - containerPort: 9090 # needed for automated tests 56 | - containerPort: 3100 # needed for automated tests 57 | - containerPort: 3200 # needed for automated tests 58 | readinessProbe: 59 | exec: 60 | command: 61 | - cat 62 | - /tmp/ready 63 | volumeMounts: 64 | - mountPath: /otel-lgtm/otelcol-config.yaml 65 | name: otel-collector-config 66 | subPath: otel-collector-config.yaml 67 | readOnly: true 68 | - mountPath: /var/log 69 | name: varlog 70 | readOnly: true 71 | - mountPath: /var/lib/docker/containers 72 | name: varlibdockercontainers 73 | readOnly: true 74 | env: 75 | - name: ENABLE_LOGS_OTELCOL 76 | value: "true" 77 | volumes: 78 | - name: otel-collector-config 79 | configMap: 80 | name: otel-collector-config 81 | - name: varlog 82 | hostPath: 83 | path: /var/log 84 | - name: varlibdockercontainers 85 | hostPath: 86 | path: /var/lib/docker/containers 87 | -------------------------------------------------------------------------------- /logging-k8s-stdout-otlp-json/oats.yaml: -------------------------------------------------------------------------------- 1 | # OATS is an acceptance testing framework for OpenTelemetry - https://github.com/grafana/oats 2 | 3 | kubernetes: 4 | dir: k8s 5 | app-service: dice 6 | app-docker-file: Dockerfile 7 | app-docker-tag: dice:1.1-SNAPSHOT 8 | app-docker-port: 8080 9 | input: 10 | - path: /rolldice 11 | expected: 12 | logs: 13 | - logql: '{service_name="dice"} |~ `.*Anonymous player is rolling the dice:.*`' 14 | regexp: 'Anonymous player is rolling the dice: \d+' # uses formatted message 15 | - logql: '{service_name="dice"} |~ `.*simulating an error.*`' 16 | equals: 'Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: java.lang.RuntimeException: simulating an error] with root cause' 17 | attributes: 18 | deployment_environment: staging 19 | exception_message: "simulating an error" 20 | exception_type: "java.lang.RuntimeException" 21 | scope_name: "org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/].[dispatcherServlet]" 22 | service_name: dice 23 | service_namespace: shop 24 | service_version: 1.1 25 | severity_number: 17 26 | severity_text: SEVERE 27 | attribute-regexp: 28 | flags: ".*" # from loki 29 | detected_level: ".*" # from loki 30 | observed_timestamp: ".*" # from loki 31 | # thread_name: ".*" # thread name is missing when there is an exception - has nothing to do with stdout logging 32 | span_id: ".*" 33 | trace_id: ".*" 34 | container_id: ".*" 35 | host_arch: ".*" 36 | host_name: ".*" 37 | os_description: ".*" 38 | os_type: ".*" 39 | process_command_args: ".*" 40 | process_executable_path: ".*" 41 | process_pid: ".*" 42 | process_runtime_description: ".*" 43 | process_runtime_name: ".*" 44 | process_runtime_version: ".*" 45 | service_instance_id: ".*" 46 | telemetry_distro_name: ".*" 47 | telemetry_distro_version: ".*" 48 | telemetry_sdk_language: ".*" 49 | telemetry_sdk_name: ".*" 50 | telemetry_sdk_version: ".*" 51 | exception_stacktrace: "java\\.lang\\.RuntimeException: simulating an error\n\tat io\\.opentelemetry\\.example\\.RollController\\.index\\(RollController\\.java:21\\)\n\t.*\n" 52 | 53 | no-extra-attributes: true 54 | 55 | -------------------------------------------------------------------------------- /logging-k8s-stdout-otlp-json/otel-collector-otlpjson-pipeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-telemetry/opentelemetry-java-examples/a37e6a837adf34bc3390d8fb26e81a4a70bbe109/logging-k8s-stdout-otlp-json/otel-collector-otlpjson-pipeline.png -------------------------------------------------------------------------------- /logging-k8s-stdout-otlp-json/otlpjson-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/open-telemetry/opentelemetry-java-examples/a37e6a837adf34bc3390d8fb26e81a4a70bbe109/logging-k8s-stdout-otlp-json/otlpjson-architecture.png -------------------------------------------------------------------------------- /logging-k8s-stdout-otlp-json/src/main/java/io/opentelemetry/example/RollController.java: -------------------------------------------------------------------------------- 1 | package io.opentelemetry.example; 2 | 3 | import java.util.Optional; 4 | import java.util.Random; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.RequestParam; 9 | import org.springframework.web.bind.annotation.RestController; 10 | 11 | @RestController 12 | public class RollController { 13 | 14 | private static final Logger logger = LoggerFactory.getLogger(RollController.class); 15 | private final Random random = new Random(0); 16 | 17 | @GetMapping("/rolldice") 18 | public String index(@RequestParam("player") Optional player) throws InterruptedException { 19 | Thread.sleep((long) (Math.abs((random.nextGaussian() + 1.0) * 200.0))); 20 | if (random.nextInt(10) < 3) { 21 | throw new RuntimeException("simulating an error"); 22 | } 23 | int result = this.getRandomNumber(1, 6); 24 | if (player.isPresent()) { 25 | logger.info("{} is rolling the dice: {}", player.get(), result); 26 | } else { 27 | logger.info("Anonymous player is rolling the dice: {}", result); 28 | } 29 | return Integer.toString(result); 30 | } 31 | 32 | public int getRandomNumber(int min, int max) { 33 | return random.nextInt(min, max + 1); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /logging-k8s-stdout-otlp-json/src/main/java/io/opentelemetry/example/SpringBootApp.java: -------------------------------------------------------------------------------- 1 | package io.opentelemetry.example; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.web.bind.annotation.RestController; 6 | 7 | @SpringBootApplication 8 | @RestController 9 | public class SpringBootApp { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(SpringBootApp.class, args); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /logging-k8s-stdout-otlp-json/src/main/resources/logback-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /logging/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("java") 3 | } 4 | 5 | description = "OpenTelemetry Examples for logging exporters" 6 | val moduleName by extra { "io.opentelemetry.examples.logging" } 7 | 8 | java { 9 | toolchain { 10 | languageVersion.set(JavaLanguageVersion.of(8)) 11 | } 12 | } 13 | 14 | dependencies { 15 | implementation("io.opentelemetry:opentelemetry-api") 16 | implementation("io.opentelemetry:opentelemetry-exporter-logging") 17 | } 18 | -------------------------------------------------------------------------------- /logging/src/main/java/io/opentelemetry/example/logging/ExampleConfiguration.java: -------------------------------------------------------------------------------- 1 | package io.opentelemetry.example.logging; 2 | 3 | import io.opentelemetry.api.OpenTelemetry; 4 | import io.opentelemetry.exporter.logging.LoggingMetricExporter; 5 | import io.opentelemetry.exporter.logging.LoggingSpanExporter; 6 | import io.opentelemetry.sdk.OpenTelemetrySdk; 7 | import io.opentelemetry.sdk.metrics.SdkMeterProvider; 8 | import io.opentelemetry.sdk.metrics.export.MetricReader; 9 | import io.opentelemetry.sdk.metrics.export.PeriodicMetricReader; 10 | import io.opentelemetry.sdk.trace.SdkTracerProvider; 11 | import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; 12 | import java.time.Duration; 13 | 14 | /** 15 | * All SDK management takes place here, away from the instrumentation code, which should only access 16 | * the OpenTelemetry APIs. 17 | */ 18 | public final class ExampleConfiguration { 19 | 20 | /** The number of milliseconds between metric exports. */ 21 | private static final long METRIC_EXPORT_INTERVAL_MS = 800L; 22 | 23 | /** 24 | * Initializes an OpenTelemetry SDK with a logging exporter and a SimpleSpanProcessor. 25 | * 26 | * @return A ready-to-use {@link OpenTelemetry} instance. 27 | */ 28 | public static OpenTelemetry initOpenTelemetry() { 29 | // Create an instance of PeriodicMetricReader and configure it 30 | // to export via the logging exporter 31 | MetricReader periodicReader = 32 | PeriodicMetricReader.builder(LoggingMetricExporter.create()) 33 | .setInterval(Duration.ofMillis(METRIC_EXPORT_INTERVAL_MS)) 34 | .build(); 35 | 36 | // This will be used to create instruments 37 | SdkMeterProvider meterProvider = 38 | SdkMeterProvider.builder().registerMetricReader(periodicReader).build(); 39 | 40 | // Tracer provider configured to export spans with SimpleSpanProcessor using 41 | // the logging exporter. 42 | SdkTracerProvider tracerProvider = 43 | SdkTracerProvider.builder() 44 | .addSpanProcessor(SimpleSpanProcessor.create(LoggingSpanExporter.create())) 45 | .build(); 46 | return OpenTelemetrySdk.builder() 47 | .setMeterProvider(meterProvider) 48 | .setTracerProvider(tracerProvider) 49 | .buildAndRegisterGlobal(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /logging/src/main/java/io/opentelemetry/example/logging/LoggingExporterExample.java: -------------------------------------------------------------------------------- 1 | package io.opentelemetry.example.logging; 2 | 3 | import io.opentelemetry.api.OpenTelemetry; 4 | import io.opentelemetry.api.metrics.LongCounter; 5 | import io.opentelemetry.api.trace.Span; 6 | import io.opentelemetry.api.trace.Tracer; 7 | 8 | /** 9 | * An example of using {@link io.opentelemetry.exporter.logging.LoggingSpanExporter} and {@link 10 | * io.opentelemetry.exporter.logging.LoggingMetricExporter}. 11 | */ 12 | public final class LoggingExporterExample { 13 | private static final String INSTRUMENTATION_NAME = LoggingExporterExample.class.getName(); 14 | 15 | private final Tracer tracer; 16 | private final LongCounter counter; 17 | 18 | public LoggingExporterExample(OpenTelemetry openTelemetry) { 19 | tracer = openTelemetry.getTracer(INSTRUMENTATION_NAME); 20 | counter = openTelemetry.getMeter(INSTRUMENTATION_NAME).counterBuilder("work_done").build(); 21 | } 22 | 23 | public void myWonderfulUseCase() { 24 | Span span = this.tracer.spanBuilder("start my wonderful use case").startSpan(); 25 | span.addEvent("Event 0"); 26 | doWork(); 27 | span.addEvent("Event 1"); 28 | span.end(); 29 | } 30 | 31 | private void doWork() { 32 | Span span = this.tracer.spanBuilder("doWork").startSpan(); 33 | try { 34 | Thread.sleep(1000); 35 | counter.add(1); 36 | } catch (InterruptedException e) { 37 | // do the right thing here 38 | } finally { 39 | span.end(); 40 | } 41 | } 42 | 43 | public static void main(String[] args) { 44 | // it is important to initialize your SDK as early as possible in your application's lifecycle 45 | OpenTelemetry oTel = ExampleConfiguration.initOpenTelemetry(); 46 | 47 | // Start the example 48 | LoggingExporterExample example = new LoggingExporterExample(oTel); 49 | // Generate a few sample spans 50 | for (int i = 0; i < 5; i++) { 51 | example.myWonderfulUseCase(); 52 | } 53 | 54 | try { 55 | // Flush out the metrics that have not yet been exported 56 | Thread.sleep(1000L); 57 | } catch (InterruptedException e) { 58 | // ignore since we're exiting 59 | } 60 | 61 | System.out.println("Bye"); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /manual-tracing/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("java") 3 | } 4 | 5 | description = "OpenTelemetry Examples for Manual Tracing" 6 | val moduleName by extra { "io.opentelemetry.examples.http" } 7 | 8 | java { 9 | toolchain { 10 | languageVersion.set(JavaLanguageVersion.of(8)) 11 | } 12 | } 13 | 14 | dependencies { 15 | implementation("io.opentelemetry:opentelemetry-api") 16 | implementation("io.opentelemetry:opentelemetry-sdk") 17 | implementation("io.opentelemetry:opentelemetry-exporter-logging") 18 | 19 | //alpha modules 20 | implementation("io.opentelemetry.semconv:opentelemetry-semconv") 21 | implementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure") 22 | implementation("io.opentelemetry:opentelemetry-api-incubator") 23 | } 24 | -------------------------------------------------------------------------------- /manual-tracing/src/main/java/io/opentelemetry/example/tracing/ExampleConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | package io.opentelemetry.example.tracing; 7 | 8 | import io.opentelemetry.api.OpenTelemetry; 9 | import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; 10 | import io.opentelemetry.context.propagation.ContextPropagators; 11 | import io.opentelemetry.exporter.logging.LoggingSpanExporter; 12 | import io.opentelemetry.sdk.OpenTelemetrySdk; 13 | import io.opentelemetry.sdk.trace.SdkTracerProvider; 14 | import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; 15 | 16 | /** 17 | * All SDK management takes place here, away from the instrumentation code, which should only access 18 | * the OpenTelemetry APIs. 19 | */ 20 | class ExampleConfiguration { 21 | 22 | /** 23 | * Initializes the OpenTelemetry SDK with a logging span exporter and the W3C Trace Context 24 | * propagator. 25 | * 26 | * @return A ready-to-use {@link OpenTelemetry} instance. 27 | */ 28 | static OpenTelemetry initOpenTelemetry() { 29 | SdkTracerProvider sdkTracerProvider = 30 | SdkTracerProvider.builder() 31 | .addSpanProcessor(SimpleSpanProcessor.create(new LoggingSpanExporter())) 32 | .build(); 33 | 34 | OpenTelemetrySdk sdk = 35 | OpenTelemetrySdk.builder() 36 | .setTracerProvider(sdkTracerProvider) 37 | .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance())) 38 | .build(); 39 | 40 | Runtime.getRuntime().addShutdownHook(new Thread(sdkTracerProvider::close)); 41 | return sdk; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /manual-tracing/src/main/java/io/opentelemetry/example/tracing/ManualTracingExample.java: -------------------------------------------------------------------------------- 1 | package io.opentelemetry.example.tracing; 2 | 3 | import io.opentelemetry.api.OpenTelemetry; 4 | import io.opentelemetry.api.baggage.Baggage; 5 | import io.opentelemetry.api.incubator.trace.ExtendedSpanBuilder; 6 | import io.opentelemetry.api.trace.Span; 7 | import io.opentelemetry.api.trace.Tracer; 8 | import io.opentelemetry.context.Context; 9 | 10 | /** 11 | * An example of using {@link io.opentelemetry.exporter.logging.LoggingSpanExporter} and {@link 12 | * io.opentelemetry.exporter.logging.LoggingMetricExporter}. 13 | */ 14 | public final class ManualTracingExample { 15 | private static final String INSTRUMENTATION_NAME = ManualTracingExample.class.getName(); 16 | 17 | private final Tracer tracer; 18 | 19 | public ManualTracingExample(OpenTelemetry openTelemetry) { 20 | tracer = openTelemetry.getTracer(INSTRUMENTATION_NAME); 21 | } 22 | 23 | public void myWonderfulUseCase() { 24 | ((ExtendedSpanBuilder) tracer.spanBuilder("calculate LLVM")).startAndCall(this::calculateLlvm); 25 | } 26 | 27 | private String calculateLlvm() { 28 | Span.current().setAttribute("type", "smarter"); 29 | //noinspection DataFlowIssue 30 | Span.current().setAttribute("foo", Baggage.current().getEntryValue("foo")); 31 | return "OK"; 32 | } 33 | 34 | public void setBaggageAndRun() { 35 | try { 36 | Baggage.current().toBuilder() 37 | .put("foo", "bar") 38 | .build() 39 | .storeInContext(Context.current()) 40 | .wrap( 41 | () -> 42 | ((ExtendedSpanBuilder) tracer.spanBuilder("span with baggage")) 43 | .startAndCall(this::calculateLlvm)) 44 | .call(); 45 | } catch (Exception e) { 46 | throw new RuntimeException(e); 47 | } 48 | } 49 | 50 | public static void main(String[] args) { 51 | // it is important to initialize your SDK as early as possible in your application's lifecycle 52 | OpenTelemetry oTel = ExampleConfiguration.initOpenTelemetry(); 53 | 54 | // Start the example 55 | ManualTracingExample example = new ManualTracingExample(oTel); 56 | // Generate a few sample spans 57 | for (int i = 0; i < 5; i++) { 58 | example.myWonderfulUseCase(); 59 | } 60 | 61 | example.setBaggageAndRun(); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /metrics/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("java") 3 | } 4 | 5 | description = "OpenTelemetry Examples for metrics" 6 | val moduleName by extra { "io.opentelemetry.examples.metrics" } 7 | 8 | java { 9 | toolchain { 10 | languageVersion.set(JavaLanguageVersion.of(17)) 11 | } 12 | } 13 | 14 | dependencies { 15 | implementation("io.opentelemetry:opentelemetry-api") 16 | 17 | implementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure") 18 | implementation("io.opentelemetry:opentelemetry-exporter-otlp") 19 | implementation("io.opentelemetry:opentelemetry-api-incubator") 20 | } 21 | -------------------------------------------------------------------------------- /metrics/src/main/java/io/opentelemetry/example/metrics/GaugeExample.java: -------------------------------------------------------------------------------- 1 | package io.opentelemetry.example.metrics; 2 | 3 | import io.opentelemetry.api.OpenTelemetry; 4 | import io.opentelemetry.api.common.Attributes; 5 | import io.opentelemetry.api.metrics.Meter; 6 | import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; 7 | 8 | /** 9 | * Example of using a Long Gauge to measure execution time of method. The gauge callback will get 10 | * executed every collection interval. This is useful for expensive measurements that would be 11 | * wastefully to calculate each request. 12 | */ 13 | public final class GaugeExample { 14 | 15 | public static void main(String[] args) { 16 | OpenTelemetry sdk = AutoConfiguredOpenTelemetrySdk.initialize().getOpenTelemetrySdk(); 17 | Meter sampleMeter = sdk.getMeter("io.opentelemetry.example.metrics"); 18 | 19 | sampleMeter 20 | .gaugeBuilder("jvm.memory.total") 21 | .setDescription("Reports JVM memory usage.") 22 | .setUnit("byte") 23 | .buildWithCallback( 24 | result -> result.record(Runtime.getRuntime().totalMemory(), Attributes.empty())); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /micrometer-shim/README.md: -------------------------------------------------------------------------------- 1 | # Micrometer Shim Example 2 | 3 | This example demonstrates a typical use case 4 | of [micrometer shim](https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/instrumentation/micrometer/micrometer-1.5/library). 5 | 6 | It consists of a spring boot application with: 7 | 8 | - A simple web API available at `GET http://localhost:8080/ping` 9 | - Instrumented with the spring boot actuator and micrometer 10 | - Micrometer metrics bridged to OpenTelemetry using the micrometer shim 11 | - OpenTelemetry metrics exported with prometheus 12 | 13 | # How to run 14 | 15 | Run the application 16 | 17 | ```shell 18 | ../gradlew bootRun 19 | ``` 20 | 21 | Exercise the application by calling its endpoint 22 | 23 | ```shell 24 | curl http://localhost:8080/ping 25 | ``` 26 | 27 | View micrometer metrics in prometheus format by navigating to: 28 | 29 | http://localhost:9464 30 | -------------------------------------------------------------------------------- /micrometer-shim/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.springframework.boot.gradle.plugin.SpringBootPlugin 2 | import org.springframework.boot.gradle.tasks.run.BootRun 3 | 4 | plugins { 5 | id("java") 6 | id("org.springframework.boot") version "3.5.0" 7 | } 8 | 9 | description = "OpenTelemetry Example for Micrometer Shim" 10 | val moduleName by extra { "io.opentelemetry.examples.micrometer-shim" } 11 | 12 | val bootRun = tasks.named("bootRun") { 13 | mainClass = "io.opentelemetry.example.micrometer.Application" 14 | } 15 | 16 | dependencies { 17 | implementation(platform(SpringBootPlugin.BOM_COORDINATES)) 18 | implementation("io.opentelemetry:opentelemetry-api") 19 | implementation("io.opentelemetry:opentelemetry-sdk") 20 | 21 | //alpha modules 22 | implementation("io.opentelemetry.instrumentation:opentelemetry-micrometer-1.5") 23 | implementation("io.opentelemetry:opentelemetry-exporter-prometheus") 24 | 25 | //spring modules 26 | implementation("org.springframework.boot:spring-boot-starter-web") 27 | implementation("org.springframework.boot:spring-boot-starter-actuator") 28 | implementation("org.springframework.boot:spring-boot-starter-aop") 29 | } 30 | -------------------------------------------------------------------------------- /micrometer-shim/src/main/java/io/opentelemetry/example/micrometer/Application.java: -------------------------------------------------------------------------------- 1 | package io.opentelemetry.example.micrometer; 2 | 3 | import io.micrometer.core.aop.TimedAspect; 4 | import io.micrometer.core.instrument.MeterRegistry; 5 | import io.opentelemetry.api.OpenTelemetry; 6 | import io.opentelemetry.exporter.prometheus.PrometheusHttpServer; 7 | import io.opentelemetry.instrumentation.micrometer.v1_5.OpenTelemetryMeterRegistry; 8 | import io.opentelemetry.sdk.OpenTelemetrySdk; 9 | import io.opentelemetry.sdk.metrics.SdkMeterProvider; 10 | import org.springframework.boot.SpringApplication; 11 | import org.springframework.boot.autoconfigure.SpringBootApplication; 12 | import org.springframework.context.annotation.Bean; 13 | 14 | @SpringBootApplication 15 | public class Application { 16 | 17 | public static void main(String[] args) { 18 | SpringApplication.run(Application.class, args); 19 | } 20 | 21 | // Configure OpenTelemetry bean, registering prometheus metric reader 22 | @Bean 23 | public OpenTelemetry openTelemetry() { 24 | return OpenTelemetrySdk.builder() 25 | .setMeterProvider( 26 | SdkMeterProvider.builder().registerMetricReader(PrometheusHttpServer.create()).build()) 27 | .build(); 28 | } 29 | 30 | // Enable @Timed annotation 31 | @Bean 32 | public TimedAspect timedAspect(MeterRegistry registry) { 33 | return new TimedAspect(registry); 34 | } 35 | 36 | // Configure OpenTelemetryMeterRegistry bean, overriding default autoconfigured MeterRegistry bean 37 | @Bean 38 | public MeterRegistry meterRegistry(OpenTelemetry openTelemetry) { 39 | return OpenTelemetryMeterRegistry.builder(openTelemetry) 40 | // Simulate behavior of micrometer's PrometheusMeterRegistry 41 | .setPrometheusMode(true) 42 | .build(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /micrometer-shim/src/main/java/io/opentelemetry/example/micrometer/Controller.java: -------------------------------------------------------------------------------- 1 | package io.opentelemetry.example.micrometer; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.web.bind.annotation.GetMapping; 5 | import org.springframework.web.bind.annotation.RestController; 6 | 7 | @RestController 8 | public class Controller { 9 | 10 | @Autowired private Service service; 11 | 12 | @GetMapping("/ping") 13 | public String ping() throws InterruptedException { 14 | service.doWork(); 15 | return "pong"; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /micrometer-shim/src/main/java/io/opentelemetry/example/micrometer/Service.java: -------------------------------------------------------------------------------- 1 | package io.opentelemetry.example.micrometer; 2 | 3 | import io.micrometer.core.annotation.Timed; 4 | import java.util.Random; 5 | import org.springframework.stereotype.Component; 6 | 7 | @Component 8 | public class Service { 9 | 10 | @Timed("dowork.time") 11 | void doWork() throws InterruptedException { 12 | Thread.sleep(new Random().nextInt(1000)); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /otlp/README.md: -------------------------------------------------------------------------------- 1 | ### Running the OTLP example 2 | 3 | Assuming you're on a unix-alike (mac, linux, etc): 4 | 5 | In a shell: 6 | ```shell 7 | cd docker 8 | docker-compose up 9 | ``` 10 | 11 | In a separate shell: 12 | ```shell 13 | ../gradlew run 14 | ``` -------------------------------------------------------------------------------- /otlp/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("java") 3 | id("application") 4 | } 5 | 6 | description = "OpenTelemetry Example for OTLP Exporters" 7 | val moduleName by extra { "io.opentelemetry.examples.otlp" } 8 | 9 | java { 10 | toolchain { 11 | languageVersion.set(JavaLanguageVersion.of(8)) 12 | } 13 | } 14 | 15 | application { 16 | mainClass = "io.opentelemetry.example.otlp.OtlpExporterExample" 17 | } 18 | 19 | dependencies { 20 | implementation("io.opentelemetry:opentelemetry-api") 21 | implementation("io.opentelemetry:opentelemetry-sdk") 22 | implementation("io.opentelemetry:opentelemetry-exporter-otlp") 23 | implementation("io.opentelemetry.semconv:opentelemetry-semconv") 24 | } 25 | -------------------------------------------------------------------------------- /otlp/docker/.env: -------------------------------------------------------------------------------- 1 | OTELCOL_IMG=otel/opentelemetry-collector-contrib:latest 2 | OTELCOL_ARGS= 3 | -------------------------------------------------------------------------------- /otlp/docker/README.md: -------------------------------------------------------------------------------- 1 | # OpenTelemetry Collector Demo 2 | 3 | *IMPORTANT:* This uses a pre-released version of the OpenTelemetry Collector. 4 | 5 | This demo uses `docker-compose` and by default runs against the 6 | `otel/opentelemetry-collector-dev:latest` image. To run the demo, switch 7 | to this directory and run: 8 | 9 | ```shell 10 | docker-compose up -d 11 | ``` 12 | 13 | The demo exposes the following backends: 14 | 15 | - Jaeger at http://0.0.0.0:16686 16 | - Zipkin at http://0.0.0.0:9411 17 | - Prometheus at http://0.0.0.0:9090 18 | 19 | Notes: 20 | 21 | - It may take some time for the application metrics to appear on the Prometheus 22 | dashboard; 23 | 24 | To clean up any docker container from the demo run `docker-compose down` from 25 | this directory. 26 | -------------------------------------------------------------------------------- /otlp/docker/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | services: 3 | 4 | # Jaeger 5 | jaeger-all-in-one: 6 | image: jaegertracing/all-in-one:latest@sha256:82505210a99b18f587c94f40120c2e13ef3a6ac3095eebdb9e9cba9bf5839efd 7 | ports: 8 | - "16686:16686" 9 | - "14268" 10 | - "14250:14250" 11 | environment: 12 | - COLLECTOR_OTLP_ENABLED=true 13 | 14 | # Zipkin 15 | zipkin-all-in-one: 16 | image: openzipkin/zipkin:latest@sha256:bb570eb45c2994eaf32da783cc098b3d51d1095b73ec92919863d73d0a9eaafb 17 | ports: 18 | - "9411:9411" 19 | 20 | # Collector 21 | otel-collector: 22 | image: ${OTELCOL_IMG} 23 | command: ["--config=/etc/otel-collector-config-demo.yaml", "${OTELCOL_ARGS}"] 24 | volumes: 25 | - ./otel-collector-config-demo.yaml:/etc/otel-collector-config-demo.yaml 26 | ports: 27 | - "1888:1888" # pprof extension 28 | - "8888:8888" # Prometheus metrics exposed by the collector 29 | - "8889:8889" # Prometheus exporter metrics 30 | - "13133:13133" # health_check extension 31 | - "55679:55679" # zpages extension 32 | - "4317:4317" # otlp receiver 33 | depends_on: 34 | - jaeger-all-in-one 35 | - zipkin-all-in-one 36 | 37 | prometheus: 38 | container_name: prometheus 39 | image: prom/prometheus:latest@sha256:9abc6cf6aea7710d163dbb28d8eeb7dc5baef01e38fa4cd146a406dd9f07f70d 40 | volumes: 41 | - ./prometheus.yaml:/etc/prometheus/prometheus.yml 42 | ports: 43 | - "9090:9090" 44 | -------------------------------------------------------------------------------- /otlp/docker/otel-collector-config-demo.yaml: -------------------------------------------------------------------------------- 1 | receivers: 2 | otlp: 3 | protocols: 4 | grpc: 5 | 6 | exporters: 7 | prometheus: 8 | endpoint: "0.0.0.0:8889" 9 | namespace: promexample 10 | const_labels: 11 | label1: value1 12 | debug: 13 | verbosity: detailed 14 | 15 | zipkin: 16 | endpoint: "http://zipkin-all-in-one:9411/api/v2/spans" 17 | format: proto 18 | 19 | otlp/jaeger: 20 | endpoint: jaeger-all-in-one:4317 21 | tls: 22 | insecure: true 23 | 24 | # Alternatively, use jaeger_thrift_http with the settings below. In this case 25 | # update the list of exporters on the traces pipeline. 26 | # 27 | # jaeger_thrift_http: 28 | # url: http://jaeger-all-in-one:14268/api/traces 29 | 30 | processors: 31 | batch: 32 | 33 | extensions: 34 | health_check: 35 | pprof: 36 | endpoint: :1888 37 | zpages: 38 | endpoint: :55679 39 | 40 | service: 41 | extensions: [pprof, zpages, health_check] 42 | pipelines: 43 | traces: 44 | receivers: [otlp] 45 | processors: [batch] 46 | exporters: [debug, zipkin, otlp/jaeger] 47 | metrics: 48 | receivers: [otlp] 49 | processors: [batch] 50 | exporters: [debug, prometheus] 51 | -------------------------------------------------------------------------------- /otlp/docker/prometheus.yaml: -------------------------------------------------------------------------------- 1 | scrape_configs: 2 | - job_name: 'otel-collector' 3 | scrape_interval: 2s 4 | static_configs: 5 | - targets: ['otel-collector:8889'] 6 | - targets: ['otel-collector:8888'] 7 | -------------------------------------------------------------------------------- /otlp/src/main/java/io/opentelemetry/example/otlp/OtlpExporterExample.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | package io.opentelemetry.example.otlp; 7 | 8 | import io.opentelemetry.api.OpenTelemetry; 9 | import io.opentelemetry.api.common.Attributes; 10 | import io.opentelemetry.api.metrics.LongCounter; 11 | import io.opentelemetry.api.metrics.LongHistogram; 12 | import io.opentelemetry.api.metrics.Meter; 13 | import io.opentelemetry.api.trace.Span; 14 | import io.opentelemetry.api.trace.Tracer; 15 | import io.opentelemetry.context.Context; 16 | import io.opentelemetry.context.Scope; 17 | 18 | /** 19 | * Example code for setting up the OTLP exporters. 20 | * 21 | *

If you wish to use this code, you'll need to run a copy of the collector locally, on the 22 | * default port. There is a docker-compose configuration for doing this in the docker subdirectory 23 | * of this module. 24 | */ 25 | public final class OtlpExporterExample { 26 | 27 | public static void main(String[] args) throws InterruptedException { 28 | // it is important to initialize your SDK as early as possible in your application's lifecycle 29 | OpenTelemetry openTelemetry = ExampleConfiguration.initOpenTelemetry(); 30 | 31 | Tracer tracer = openTelemetry.getTracer("io.opentelemetry.example"); 32 | Meter meter = openTelemetry.getMeter("io.opentelemetry.example"); 33 | LongCounter counter = meter.counterBuilder("example_counter").build(); 34 | LongHistogram histogram = meter.histogramBuilder("super_timer").ofLongs().setUnit("ms").build(); 35 | 36 | for (int i = 0; i < 100; i++) { 37 | long startTime = System.currentTimeMillis(); 38 | Span exampleSpan = tracer.spanBuilder("exampleSpan").startSpan(); 39 | Context exampleContext = Context.current().with(exampleSpan); 40 | try (Scope scope = exampleContext.makeCurrent()) { 41 | counter.add(1); 42 | exampleSpan.setAttribute("good", true); 43 | exampleSpan.setAttribute("exampleNumber", i); 44 | Thread.sleep(100); 45 | } finally { 46 | histogram.record( 47 | System.currentTimeMillis() - startTime, Attributes.empty(), exampleContext); 48 | exampleSpan.end(); 49 | } 50 | } 51 | 52 | // sleep for a bit to let everything settle 53 | Thread.sleep(2000); 54 | 55 | System.out.println("Bye"); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /prometheus/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM eclipse-temurin:11-jre 2 | 3 | ADD build/libs/opentelemetry-examples-prometheus-*-SNAPSHOT-all.jar /app.jar 4 | 5 | ENTRYPOINT java -cp app.jar io.opentelemetry.example.prometheus.PrometheusExample 19090 -------------------------------------------------------------------------------- /prometheus/README.md: -------------------------------------------------------------------------------- 1 | # Prometheus Example 2 | 3 | This example demonstrates how to use the OpenTelemetry SDK to instrument a 4 | simple application using Prometheus as the metric exporter and expose the 5 | metrics via HTTP. 6 | 7 | These are collected by a Prometheus instance which is configured to pull these 8 | metrics via HTTP. 9 | 10 | # How to run 11 | 12 | ## Prerequisites 13 | 14 | * Java 1.7 15 | * Docker 19.03 16 | * Docker compose 17 | 18 | ## 1 - Compile 19 | 20 | ```shell script 21 | ../gradlew shadowJar 22 | ``` 23 | 24 | ## 2 - Run 25 | 26 | Start the application and prometheus via docker compose 27 | 28 | ```shell 29 | docker-compose up 30 | ``` 31 | 32 | ## 3 - View metrics 33 | 34 | To view metrics in prometheus, navigate to: 35 | 36 | http://localhost:9090/graph?g0.range_input=15m&g0.expr=incoming_messages&g0.tab=0 37 | 38 | To fetch application metrics in prometheus format, run: 39 | 40 | curl localhost:19090/metrics 41 | 42 | To fetch application metrics in OpenMetrics format, which includes exemplars, run: 43 | 44 | curl -H 'Accept: application/openmetrics-text; version=1.0.0; charset=utf-8' localhost:19090/metrics 45 | -------------------------------------------------------------------------------- /prometheus/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("java") 3 | } 4 | 5 | description = "OpenTelemetry Example for Prometheus Exporter" 6 | val moduleName by extra { "io.opentelemetry.examples.prometheus" } 7 | 8 | java { 9 | toolchain { 10 | languageVersion.set(JavaLanguageVersion.of(8)) 11 | } 12 | } 13 | 14 | dependencies { 15 | implementation("io.opentelemetry:opentelemetry-api") 16 | implementation("io.opentelemetry:opentelemetry-sdk") 17 | implementation("io.opentelemetry:opentelemetry-exporter-logging") 18 | implementation("io.opentelemetry.semconv:opentelemetry-semconv") 19 | 20 | //alpha modules 21 | implementation("io.opentelemetry:opentelemetry-exporter-prometheus") 22 | } 23 | -------------------------------------------------------------------------------- /prometheus/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | app: 4 | build: ./ 5 | ports: 6 | - '19090:19090' 7 | prometheus: 8 | image: prom/prometheus@sha256:9abc6cf6aea7710d163dbb28d8eeb7dc5baef01e38fa4cd146a406dd9f07f70d 9 | volumes: 10 | - ./prometheus.yml:/etc/prometheus/prometheus.yml 11 | depends_on: 12 | - app 13 | ports: 14 | - '9090:9090' 15 | -------------------------------------------------------------------------------- /prometheus/prometheus.yml: -------------------------------------------------------------------------------- 1 | global: 2 | scrape_interval: 15s 3 | scrape_timeout: 10s 4 | evaluation_interval: 15s 5 | alerting: 6 | alertmanagers: 7 | - static_configs: 8 | - targets: [] 9 | scheme: http 10 | timeout: 10s 11 | api_version: v1 12 | scrape_configs: 13 | - job_name: prometheus 14 | honor_timestamps: true 15 | scrape_interval: 15s 16 | scrape_timeout: 10s 17 | metrics_path: /metrics 18 | scheme: http 19 | static_configs: 20 | - targets: 21 | - localhost:9090 22 | - job_name: otel_java_prometheus_example 23 | honor_timestamps: true 24 | scrape_interval: 15s 25 | scrape_timeout: 10s 26 | metrics_path: /metrics 27 | scheme: http 28 | static_configs: 29 | - targets: 30 | - app:19090 31 | -------------------------------------------------------------------------------- /prometheus/src/main/java/io/opentelemetry/example/prometheus/ExampleConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | package io.opentelemetry.example.prometheus; 7 | 8 | import static io.opentelemetry.semconv.ServiceAttributes.SERVICE_NAME; 9 | 10 | import io.opentelemetry.api.OpenTelemetry; 11 | import io.opentelemetry.exporter.logging.LoggingSpanExporter; 12 | import io.opentelemetry.exporter.prometheus.PrometheusHttpServer; 13 | import io.opentelemetry.sdk.OpenTelemetrySdk; 14 | import io.opentelemetry.sdk.metrics.SdkMeterProvider; 15 | import io.opentelemetry.sdk.resources.Resource; 16 | import io.opentelemetry.sdk.trace.SdkTracerProvider; 17 | import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; 18 | 19 | public final class ExampleConfiguration { 20 | 21 | /** 22 | * Initializes the OpenTelemetry SDK and configures the prometheus collector with all default 23 | * settings. 24 | * 25 | * @param prometheusPort the port to open up for scraping. 26 | * @return a ready-to-use {@link OpenTelemetry} instance. 27 | */ 28 | static OpenTelemetry initOpenTelemetry(int prometheusPort) { 29 | // Include required service.name resource attribute on all spans and metrics 30 | Resource resource = 31 | Resource.getDefault() 32 | .merge(Resource.builder().put(SERVICE_NAME, "PrometheusExporterExample").build()); 33 | 34 | OpenTelemetrySdk openTelemetrySdk = 35 | OpenTelemetrySdk.builder() 36 | .setTracerProvider( 37 | SdkTracerProvider.builder() 38 | .setResource(resource) 39 | .addSpanProcessor(SimpleSpanProcessor.create(LoggingSpanExporter.create())) 40 | .build()) 41 | .setMeterProvider( 42 | SdkMeterProvider.builder() 43 | .setResource(resource) 44 | .registerMetricReader( 45 | PrometheusHttpServer.builder().setPort(prometheusPort).build()) 46 | .build()) 47 | .buildAndRegisterGlobal(); 48 | 49 | Runtime.getRuntime().addShutdownHook(new Thread(openTelemetrySdk::close)); 50 | 51 | return openTelemetrySdk; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /prometheus/src/main/java/io/opentelemetry/example/prometheus/PrometheusExample.java: -------------------------------------------------------------------------------- 1 | package io.opentelemetry.example.prometheus; 2 | 3 | import io.opentelemetry.api.OpenTelemetry; 4 | import io.opentelemetry.api.common.Attributes; 5 | import io.opentelemetry.api.metrics.LongCounter; 6 | import io.opentelemetry.api.metrics.LongHistogram; 7 | import io.opentelemetry.api.metrics.Meter; 8 | import io.opentelemetry.api.trace.Span; 9 | import io.opentelemetry.api.trace.Tracer; 10 | import io.opentelemetry.context.Context; 11 | import io.opentelemetry.context.Scope; 12 | 13 | /** 14 | * Example of using the PrometheusHttpServer to convert OTel metrics to Prometheus format and expose 15 | * these to a Prometheus instance via a HttpServer exporter. 16 | * 17 | *

A Gauge is used to periodically measure how many incoming messages are awaiting processing. 18 | * The Gauge callback gets executed every collection interval. 19 | */ 20 | public final class PrometheusExample { 21 | public static void main(String[] args) throws InterruptedException { 22 | int prometheusPort = 0; 23 | try { 24 | prometheusPort = Integer.parseInt(args[0]); 25 | } catch (Exception e) { 26 | System.out.println("Port not set, or is invalid. Exiting"); 27 | System.exit(1); 28 | } 29 | // it is important to initialize your SDK as early as possible in your application's lifecycle 30 | OpenTelemetry openTelemetry = ExampleConfiguration.initOpenTelemetry(prometheusPort); 31 | 32 | Tracer tracer = openTelemetry.getTracer("io.opentelemetry.example.prometheus"); 33 | Meter meter = openTelemetry.getMeter("io.opentelemetry.example.prometheus"); 34 | LongCounter counter = meter.counterBuilder("example.counter").build(); 35 | LongHistogram histogram = meter.histogramBuilder("super.timer").ofLongs().setUnit("ms").build(); 36 | 37 | for (int i = 0; i < 500; i++) { 38 | long startTime = System.currentTimeMillis(); 39 | Span exampleSpan = tracer.spanBuilder("exampleSpan").startSpan(); 40 | Context exampleContext = Context.current().with(exampleSpan); 41 | try (Scope scope = exampleContext.makeCurrent()) { 42 | counter.add(1); 43 | exampleSpan.setAttribute("good", true); 44 | exampleSpan.setAttribute("exampleNumber", i); 45 | Thread.sleep(1000); 46 | } finally { 47 | histogram.record( 48 | System.currentTimeMillis() - startTime, Attributes.empty(), exampleContext); 49 | exampleSpan.end(); 50 | } 51 | } 52 | 53 | System.out.println("Exiting"); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /resource-detection-gcp/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("java") 3 | id("application") 4 | id("com.google.cloud.tools.jib") 5 | } 6 | 7 | description = "OpenTelemetry Example for Google Cloud Resource Detection" 8 | val moduleName by extra { "io.opentelemetry.examples.resource-detection.gcp" } 9 | 10 | val autoconfConfig = listOf( 11 | "-Dotel.traces.exporter=logging-otlp", 12 | "-Dotel.metrics.exporter=none", 13 | "-Dotel.logs.exporter=none", 14 | "-Dotel.java.global-autoconfigure.enabled=true", 15 | "-Dotel.service.name=opentelemetry-examples-resource-gcp", 16 | ) 17 | 18 | java { 19 | toolchain { 20 | languageVersion.set(JavaLanguageVersion.of(8)) 21 | } 22 | } 23 | 24 | application { 25 | mainClass = "io.opentelemetry.resource.gcp.GCPResourceExample" 26 | applicationDefaultJvmArgs = autoconfConfig 27 | } 28 | 29 | dependencies { 30 | implementation("io.opentelemetry:opentelemetry-api") 31 | implementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure") 32 | implementation("io.opentelemetry:opentelemetry-exporter-logging-otlp") 33 | implementation("io.opentelemetry.contrib:opentelemetry-gcp-resources:1.46.0-alpha") 34 | } 35 | 36 | jib { 37 | from.image = "gcr.io/distroless/java-debian10:11" 38 | containerizingMode = "packaged" 39 | container.jvmFlags = autoconfConfig 40 | } 41 | -------------------------------------------------------------------------------- /resource-detection-gcp/k8s/job.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | # Unique key of the Job instance 5 | name: hello-resource-java 6 | spec: 7 | template: 8 | metadata: 9 | name: hello-resource-java 10 | labels: 11 | service: hello-resource-java 12 | spec: 13 | containers: 14 | - name: hello-resource-java 15 | image: "%REGISTRY_LOCATION%-docker.pkg.dev/%GOOGLE_CLOUD_PROJECT%/%ARTIFACT_REGISTRY%/hello-resource-java:latest" 16 | env: 17 | - name: OTEL_TRACES_EXPORTER 18 | value: none 19 | - name: OTEL_METRICS_EXPORTER 20 | value: none 21 | - name: OTEL_LOGS_EXPORTER 22 | value: none 23 | - name: OTEL_SERVICE_NAME 24 | valueFrom: 25 | fieldRef: 26 | fieldPath: metadata.labels['service'] 27 | - name: POD_NAME 28 | valueFrom: 29 | fieldRef: 30 | fieldPath: metadata.name 31 | - name: NAMESPACE_NAME 32 | valueFrom: 33 | fieldRef: 34 | fieldPath: metadata.namespace 35 | - name: CONTAINER_NAME 36 | value: hello-resource-java 37 | - name: OTEL_RESOURCE_ATTRIBUTES 38 | value: k8s.pod.name=$(POD_NAME),k8s.namespace.name=$(NAMESPACE_NAME),k8s.container.name=$(CONTAINER_NAME) 39 | # Do not restart containers after they exit 40 | restartPolicy: Never 41 | # of retries before marking as failed. 42 | backoffLimit: 4 43 | -------------------------------------------------------------------------------- /resource-detection-gcp/src/main/java/io/opentelemetry/resource/gcp/GCPResourceExample.java: -------------------------------------------------------------------------------- 1 | package io.opentelemetry.resource.gcp; 2 | 3 | import io.opentelemetry.api.trace.Span; 4 | import io.opentelemetry.context.Scope; 5 | import io.opentelemetry.contrib.gcp.resource.GCPResourceProvider; 6 | import io.opentelemetry.sdk.OpenTelemetrySdk; 7 | import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; 8 | import io.opentelemetry.sdk.autoconfigure.ResourceConfiguration; 9 | import io.opentelemetry.sdk.common.CompletableResultCode; 10 | import io.opentelemetry.sdk.resources.Resource; 11 | import java.util.concurrent.TimeUnit; 12 | 13 | public class GCPResourceExample { 14 | private static final String INSTRUMENTATION_SCOPE_NAME = GCPResourceExample.class.getName(); 15 | 16 | public static void main(String[] args) { 17 | // Get the autoconfigured OpenTelemetry SDK 18 | OpenTelemetrySdk openTelemetrySdk = 19 | AutoConfiguredOpenTelemetrySdk.initialize().getOpenTelemetrySdk(); 20 | 21 | // Shows the resource attributes detected from the environment variables 22 | // and system properties. 23 | System.out.println("Detecting resource: Environment"); 24 | Resource autoResource = ResourceConfiguration.createEnvironmentResource(); 25 | System.out.println(autoResource.getAttributes() + "\n"); 26 | 27 | // Shows the resource attributes detected by the GCP Resource Provider 28 | System.out.println("Detecting resource: hardcoded"); 29 | GCPResourceProvider resourceProvider = new GCPResourceProvider(); 30 | System.out.println(resourceProvider.getAttributes() + "\n"); 31 | 32 | // Shows the attributes attached to the Resource that was set for TracerProvider 33 | // via the autoconfiguration SPI. 34 | System.out.println("Detecting resource: Autoconfigure"); 35 | Span span = 36 | openTelemetrySdk 37 | .getTracer(INSTRUMENTATION_SCOPE_NAME) 38 | .spanBuilder("gcp-resource-detection") 39 | .startSpan(); 40 | try (Scope ignored = span.makeCurrent()) { 41 | // Simulate work: this could be simulating a network request or an expensive disk operation 42 | Thread.sleep(500); 43 | } catch (InterruptedException e) { 44 | throw new RuntimeException(e); 45 | } finally { 46 | span.end(); 47 | } 48 | // Flush all buffered traces 49 | CompletableResultCode completableResultCode = 50 | openTelemetrySdk.getSdkTracerProvider().shutdown(); 51 | // wait till export finishes 52 | completableResultCode.join(10000, TimeUnit.MILLISECONDS); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /sdk-usage/README.md: -------------------------------------------------------------------------------- 1 | # SDK Usage Examples 2 | 3 | This is a simple example that demonstrates how to use and configure the OpenTelemetry SDK. 4 | 5 | ## Prerequisites 6 | * Java 1.8 or higher 7 | 8 | 9 | ## Compile 10 | Compile with 11 | ```shell script 12 | ../gradlew shadowJar 13 | ``` 14 | 15 | ## Run 16 | 17 | The following commands are used to run the examples. 18 | ```shell script 19 | java -cp build/libs/opentelemetry-examples-sdk-usage-0.1.0-SNAPSHOT-all.jar io.opentelemetry.sdk.example.ConfigureTraceExample 20 | ``` 21 | ```shell script 22 | java -cp build/libs/opentelemetry-examples-sdk-usage-0.1.0-SNAPSHOT-all.jar io.opentelemetry.sdk.example.ConfigureSpanProcessorExample 23 | ``` -------------------------------------------------------------------------------- /sdk-usage/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("java") 3 | } 4 | 5 | description = "OpenTelemetry Examples for SDK Usage" 6 | val moduleName by extra { "io.opentelemetry.examples.sdk.usage" } 7 | 8 | java { 9 | toolchain { 10 | languageVersion.set(JavaLanguageVersion.of(8)) 11 | } 12 | } 13 | 14 | dependencies { 15 | implementation("io.opentelemetry:opentelemetry-sdk") 16 | implementation("io.opentelemetry:opentelemetry-exporter-logging") 17 | } 18 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | plugins { 3 | id("com.diffplug.spotless") version "7.0.4" 4 | id("com.github.johnrengelman.shadow") version "8.1.1" 5 | id("com.google.protobuf") version "0.9.5" 6 | id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0" 7 | id("com.google.cloud.tools.jib") version "3.4.5" 8 | id("com.gradle.develocity") version "4.0.2" 9 | } 10 | } 11 | 12 | plugins { 13 | id("org.gradle.toolchains.foojay-resolver-convention") 14 | id("com.gradle.develocity") 15 | } 16 | 17 | develocity { 18 | buildScan { 19 | publishing.onlyIf { System.getenv("CI") != null } 20 | termsOfUseUrl.set("https://gradle.com/help/legal-terms-of-use") 21 | termsOfUseAgree.set("yes") 22 | } 23 | } 24 | 25 | rootProject.name = "opentelemetry-java-examples" 26 | include( 27 | ":opentelemetry-examples-autoconfigure", 28 | ":opentelemetry-examples-declarative-configuration", 29 | ":opentelemetry-examples-http", 30 | ":opentelemetry-examples-jaeger", 31 | ":opentelemetry-examples-javaagent", 32 | ":opentelemetry-examples-log-appender", 33 | ":opentelemetry-examples-logging", 34 | ":opentelemetry-examples-logging-k8s-stdout-otlp-json", 35 | ":opentelemetry-examples-manual-tracing", 36 | ":opentelemetry-examples-metrics", 37 | ":opentelemetry-examples-micrometer-shim", 38 | ":opentelemetry-examples-otlp", 39 | ":opentelemetry-examples-prometheus", 40 | ":opentelemetry-examples-sdk-usage", 41 | ":opentelemetry-examples-telemetry-testing", 42 | ":opentelemetry-examples-zipkin", 43 | ":opentelemetry-examples-spring-native", 44 | ":opentelemetry-examples-kotlin-extension", 45 | ":opentelemetry-examples-grpc", 46 | ":opentelemetry-examples-resource-detection-gcp", 47 | ":doc-snippets:api", 48 | ":doc-snippets:configuration", 49 | ":doc-snippets:getting-started", 50 | ":doc-snippets:exporters", 51 | ":doc-snippets:spring-starter", 52 | ) 53 | 54 | rootProject.children.forEach { 55 | if (it.name != "doc-snippets") { 56 | it.projectDir = file( 57 | "$rootDir/${it.name}".replace("opentelemetry-examples-", "") 58 | ) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /spring-native/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.springframework.boot.gradle.plugin.SpringBootPlugin 2 | 3 | plugins { 4 | id("java") 5 | id("org.springframework.boot") version "3.5.0" 6 | id("org.graalvm.buildtools.native") version "0.10.6" 7 | } 8 | 9 | description = "OpenTelemetry Example for Spring native images" 10 | val moduleName by extra { "io.opentelemetry.examples.native" } 11 | 12 | dependencies { 13 | implementation(platform(SpringBootPlugin.BOM_COORDINATES)) 14 | implementation(platform("io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom:2.16.0")) 15 | implementation("org.springframework.boot:spring-boot-starter-actuator") 16 | implementation("org.springframework.boot:spring-boot-starter-web") 17 | implementation("org.springframework.boot:spring-boot-starter-data-jdbc") 18 | implementation("com.h2database:h2") 19 | implementation("io.opentelemetry.instrumentation:opentelemetry-spring-boot-starter") 20 | 21 | // for otelCustomizer in Application.java 22 | implementation("io.opentelemetry.contrib:opentelemetry-samplers:1.46.0-alpha") 23 | } 24 | -------------------------------------------------------------------------------- /spring-native/collector-spring-native-config.yaml: -------------------------------------------------------------------------------- 1 | receivers: 2 | otlp: 3 | protocols: 4 | http: 5 | endpoint: "0.0.0.0:4318" 6 | exporters: 7 | debug: 8 | verbosity: detailed 9 | service: 10 | pipelines: 11 | metrics: 12 | receivers: [otlp] 13 | exporters: [debug] 14 | traces: 15 | receivers: [otlp] 16 | exporters: [debug] 17 | logs: 18 | receivers: [otlp] 19 | exporters: [debug] 20 | -------------------------------------------------------------------------------- /spring-native/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | services: 3 | app: 4 | image: otel-native-graalvm 5 | environment: 6 | OTEL_SERVICE_NAME: "graal-native-example-app" 7 | OTEL_EXPORTER_OTLP_ENDPOINT: "http://collector:4318" 8 | ports: 9 | - "8080:8080" 10 | depends_on: 11 | - collector 12 | collector: 13 | image: otel/opentelemetry-collector-contrib:0.127.0@sha256:e94cfd92357aa21f4101dda3c0c01f90e6f24115ba91b263c4d09fed7911ae68 14 | volumes: 15 | - ./collector-spring-native-config.yaml:/collector-spring-native-config.yaml 16 | command: ["--config=/collector-spring-native-config.yaml"] 17 | expose: 18 | - "4317" 19 | ports: 20 | - "4317:4317" 21 | -------------------------------------------------------------------------------- /spring-native/src/main/java/io/opentelemetry/example/graal/Application.java: -------------------------------------------------------------------------------- 1 | package io.opentelemetry.example.graal; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Application { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(Application.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /spring-native/src/main/java/io/opentelemetry/example/graal/Controller.java: -------------------------------------------------------------------------------- 1 | package io.opentelemetry.example.graal; 2 | 3 | import org.springframework.web.bind.annotation.GetMapping; 4 | import org.springframework.web.bind.annotation.RestController; 5 | 6 | @RestController 7 | public class Controller { 8 | 9 | @GetMapping("/ping") 10 | public String ping() { 11 | return "pong"; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /spring-native/src/main/java/io/opentelemetry/example/graal/OpenTelemetryConfig.java: -------------------------------------------------------------------------------- 1 | package io.opentelemetry.example.graal; 2 | 3 | import io.opentelemetry.api.trace.SpanKind; 4 | import io.opentelemetry.contrib.sampler.RuleBasedRoutingSampler; 5 | import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter; 6 | import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider; 7 | import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; 8 | import io.opentelemetry.sdk.trace.export.SpanExporter; 9 | import io.opentelemetry.sdk.trace.samplers.Sampler; 10 | import io.opentelemetry.semconv.UrlAttributes; 11 | import java.util.Collections; 12 | import java.util.Map; 13 | import org.springframework.context.annotation.Bean; 14 | import org.springframework.context.annotation.Configuration; 15 | 16 | @Configuration 17 | public class OpenTelemetryConfig { 18 | 19 | @Bean 20 | public AutoConfigurationCustomizerProvider otelCustomizer() { 21 | return p -> 22 | p.addSamplerCustomizer(this::configureSampler) 23 | .addSpanExporterCustomizer(this::configureSpanExporter); 24 | } 25 | 26 | /** suppress spans for actuator endpoints */ 27 | private RuleBasedRoutingSampler configureSampler(Sampler fallback, ConfigProperties config) { 28 | return RuleBasedRoutingSampler.builder(SpanKind.SERVER, fallback) 29 | .drop(UrlAttributes.URL_PATH, "^/actuator") 30 | .build(); 31 | } 32 | 33 | /** 34 | * Configuration for the OTLP exporter. This configuration will replace the default OTLP exporter, 35 | * and will add a custom header to the requests. 36 | */ 37 | private SpanExporter configureSpanExporter(SpanExporter exporter, ConfigProperties config) { 38 | if (exporter instanceof OtlpHttpSpanExporter) { 39 | return ((OtlpHttpSpanExporter) exporter).toBuilder().setHeaders(this::headers).build(); 40 | } 41 | return exporter; 42 | } 43 | 44 | private Map headers() { 45 | return Collections.singletonMap("Authorization", "Bearer " + refreshToken()); 46 | } 47 | 48 | private String refreshToken() { 49 | // e.g. read the token from a kubernetes secret 50 | return "token"; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /spring-native/src/main/java/io/opentelemetry/example/graal/SqlExecutor.java: -------------------------------------------------------------------------------- 1 | package io.opentelemetry.example.graal; 2 | 3 | import org.springframework.boot.context.event.ApplicationReadyEvent; 4 | import org.springframework.context.event.EventListener; 5 | import org.springframework.jdbc.core.JdbcTemplate; 6 | import org.springframework.stereotype.Component; 7 | 8 | @Component 9 | public class SqlExecutor { 10 | 11 | private final JdbcTemplate jdbcTemplate; 12 | 13 | public SqlExecutor(JdbcTemplate jdbcTemplate) { 14 | this.jdbcTemplate = jdbcTemplate; 15 | } 16 | 17 | @EventListener(ApplicationReadyEvent.class) 18 | public void loadData() { 19 | jdbcTemplate.execute("create table test_table (id bigint not null, primary key (id))"); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /spring-native/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.datasource.url=jdbc:h2:mem:db 2 | management.endpoints.web.exposure.include=* 3 | -------------------------------------------------------------------------------- /telemetry-testing/README.md: -------------------------------------------------------------------------------- 1 | # Telemetry testing Example 2 | 3 | This is an example how to test the telemetry data using [MockServer](https://www.mock-server.com/). 4 | 5 | The example contains a simple SpringBoot application that exposes an API available at `GET http://localhost:8080/ping` 6 | 7 | ## Telemetry 8 | 9 | When the API is called, auto instrumentation from the OpenTelemetry Java Agent records traces and 10 | metrics. 11 | 12 | The method `doWork()` in Controller class is annotated with the `@WithSpan` annotation which automatically generates the trace when the method is called. 13 | Counter meter `apiCounter` increments the metric on each API call. 14 | 15 | ## Prerequisites 16 | * Java 1.8 or higher 17 | 18 | ## Run 19 | 20 | Go to test folder and execute the test from ApplicationTest class. 21 | 22 | ApplicationTest contains 1 test `testTelemetry()` which verifies that: 23 | - the traces `Controller.doWork` and `Controller.ping` were sent to the collector 24 | - metric `apiCounter` was sent to the collector 25 | 26 | when the API was called. 27 | 28 | ### Test set up 29 | 30 | Gradle build script contains a task to download the OpenTelemetry Java Agent jar, which is added to the jvm arguments in the `test` task. 31 | 32 | Additionally, the OpenTelemetry is configured with properties: 33 | - otel.exporter.otlp.protocol=http/protobuf - set up the telemetry protocol, default is grpc 34 | - otel.metric.export.interval=5000 - set up the interval, between the start of two export attempts, default is 60s 35 | More information about the configuration can be found in this [OpenTelemetry doc](https://github.com/open-telemetry/opentelemetry-java/blob/main/sdk-extensions/autoconfigure/README.md#otlp-exporter-span-metric-and-log-exporters). 36 | 37 | The MockServer library is used to mock the collector web server. It's configured with port `4318`, because for 38 | `http/protobuf` protocol, the otel exporter endpoint is by default set to `http://localhost:4318`. 39 | 40 | The collector mock server is configured with expectation to reply with http code 200 on every request. 41 | 42 | To verify that the telemetry was sent to the collector we retrieve the requests from the mock server and assert the traces and metrics names. 43 | 44 | -------------------------------------------------------------------------------- /telemetry-testing/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.springframework.boot.gradle.plugin.SpringBootPlugin 2 | import org.springframework.boot.gradle.tasks.bundling.BootJar 3 | import org.springframework.boot.gradle.tasks.run.BootRun 4 | 5 | plugins { 6 | id("java") 7 | id("org.springframework.boot") version "3.5.0" 8 | } 9 | 10 | description = "OpenTelemetry Example for Telemetry Testing" 11 | val moduleName by extra { "io.opentelemetry.examples.telemetry-testing" } 12 | 13 | val bootRun = tasks.named("bootRun") { 14 | mainClass = "io.opentelemetry.example.javagent.Application" 15 | } 16 | 17 | val agent = configurations.create("agent") 18 | 19 | val bootJar = tasks.named("bootJar") { 20 | dependsOn(agent) 21 | } 22 | 23 | dependencies { 24 | implementation(platform(SpringBootPlugin.BOM_COORDINATES)) 25 | implementation("io.opentelemetry:opentelemetry-api") 26 | implementation("io.opentelemetry.instrumentation:opentelemetry-instrumentation-annotations:2.16.0") 27 | //spring modules 28 | implementation("org.springframework.boot:spring-boot-starter-web") 29 | testImplementation("org.springframework.boot:spring-boot-starter-test") 30 | 31 | testImplementation(enforcedPlatform("org.junit:junit-bom:5.13.0")) 32 | testImplementation("org.junit.jupiter:junit-jupiter-api") 33 | testImplementation("org.junit.jupiter:junit-jupiter-engine") 34 | testImplementation("org.mock-server:mockserver-netty:5.15.0") 35 | testImplementation("org.awaitility:awaitility:4.3.0") 36 | testImplementation("io.opentelemetry.proto:opentelemetry-proto:1.7.0-alpha") 37 | testImplementation("org.assertj:assertj-core:3.27.3") 38 | 39 | agent("io.opentelemetry.javaagent:opentelemetry-javaagent:2.16.0") 40 | } 41 | 42 | tasks.test { 43 | useJUnitPlatform() 44 | 45 | // Add opentelemetry Java Agent jar to JVM args 46 | // otel.exporter.otlp.protocol - the transport protocol to use on OTLP trace, metric, and log requests 47 | // otel.metric.export.interval - the interval, in milliseconds, between the start of two export attempts 48 | // More information: https://github.com/open-telemetry/opentelemetry-java/blob/main/sdk-extensions/autoconfigure/README.md 49 | // 50 | // mockserver.logLevel=off is needed to avoid circular exporting of log records 51 | jvmArgs = listOf("-javaagent:${agent.singleFile}", "-Dotel.metric.export.interval=5000", "-Dmockserver.logLevel=off") 52 | } 53 | -------------------------------------------------------------------------------- /telemetry-testing/src/main/java/io/opentelemetry/example/telemetry/Application.java: -------------------------------------------------------------------------------- 1 | package io.opentelemetry.example.telemetry; 2 | 3 | import io.opentelemetry.api.GlobalOpenTelemetry; 4 | import io.opentelemetry.api.OpenTelemetry; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | import org.springframework.context.annotation.Bean; 8 | 9 | @SpringBootApplication 10 | public class Application { 11 | 12 | public static void main(String[] args) { 13 | SpringApplication.run(Application.class, args); 14 | } 15 | 16 | @Bean 17 | public OpenTelemetry openTelemetry() { 18 | return GlobalOpenTelemetry.get(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /telemetry-testing/src/main/java/io/opentelemetry/example/telemetry/Controller.java: -------------------------------------------------------------------------------- 1 | package io.opentelemetry.example.telemetry; 2 | 3 | import io.opentelemetry.api.OpenTelemetry; 4 | import io.opentelemetry.api.metrics.LongCounter; 5 | import io.opentelemetry.api.metrics.Meter; 6 | import io.opentelemetry.api.trace.Tracer; 7 | import io.opentelemetry.instrumentation.annotations.WithSpan; 8 | import java.util.Random; 9 | import org.apache.logging.log4j.LogManager; 10 | import org.apache.logging.log4j.Logger; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.web.bind.annotation.GetMapping; 13 | import org.springframework.web.bind.annotation.RestController; 14 | 15 | @RestController 16 | public class Controller { 17 | 18 | private static final Logger LOGGER = LogManager.getLogger(Controller.class); 19 | 20 | private final Random random = new Random(); 21 | private final Tracer tracer; 22 | private final Meter meter; 23 | private final LongCounter counter; 24 | 25 | @Autowired 26 | Controller(OpenTelemetry openTelemetry) { 27 | tracer = openTelemetry.getTracer(Application.class.getName()); 28 | meter = openTelemetry.getMeter(Application.class.getName()); 29 | counter = meter.counterBuilder("apiCounter").build(); 30 | } 31 | 32 | @GetMapping("/ping") 33 | public String ping() throws InterruptedException { 34 | int sleepTime = random.nextInt(200); 35 | counter.add(1); 36 | doWork(sleepTime); 37 | return "pong"; 38 | } 39 | 40 | @WithSpan 41 | private void doWork(int sleepTime) throws InterruptedException { 42 | Thread.sleep(sleepTime); 43 | LOGGER.info("A sample log message!"); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /zipkin/README.md: -------------------------------------------------------------------------------- 1 | # Zipkin Example 2 | 3 | This is a simple example that demonstrates how to use the OpenTelemetry SDK 4 | to instrument a simple application using Zipkin as trace exporter. 5 | 6 | # How to run 7 | 8 | ## Prerequisites 9 | * Java 1.8.231 10 | * Docker 19.03 11 | 12 | ## 1 - Compile 13 | ```shell script 14 | ../gradlew shadowJar 15 | ``` 16 | ## 2 - Run Zipkin 17 | 18 | ```shell script 19 | docker run --rm -it --name zipkin \ 20 | -p 9411:9411 \ 21 | openzipkin/zipkin:latest 22 | ``` 23 | 24 | ## 3 - Start the Application 25 | ```shell script 26 | java -cp build/libs/opentelemetry-examples-zipkin-0.1.0-SNAPSHOT-all.jar io.opentelemetry.example.zipkin.ZipkinExample localhost 9411 27 | ``` 28 | ## 4 - Open the Zipkin UI 29 | 30 | Navigate to http://localhost:9411/zipkin and click on search. 31 | 32 | [zipkin]:[https://zipkin.io/] 33 | -------------------------------------------------------------------------------- /zipkin/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("java") 3 | } 4 | 5 | description = "OpenTelemetry Examples for Zipkin Exporter" 6 | val moduleName by extra { "io.opentelemetry.examples.zipkin" } 7 | 8 | java { 9 | toolchain { 10 | languageVersion.set(JavaLanguageVersion.of(8)) 11 | } 12 | } 13 | 14 | dependencies { 15 | implementation("io.opentelemetry:opentelemetry-api") 16 | implementation("io.opentelemetry:opentelemetry-sdk") 17 | implementation("io.opentelemetry:opentelemetry-exporter-zipkin") 18 | 19 | //alpha module 20 | implementation("io.opentelemetry.semconv:opentelemetry-semconv") 21 | } 22 | -------------------------------------------------------------------------------- /zipkin/src/main/java/io/opentelemetry/example/zipkin/ExampleConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright The OpenTelemetry Authors 3 | * SPDX-License-Identifier: Apache-2.0 4 | */ 5 | 6 | package io.opentelemetry.example.zipkin; 7 | 8 | import static io.opentelemetry.semconv.ServiceAttributes.SERVICE_NAME; 9 | 10 | import io.opentelemetry.api.OpenTelemetry; 11 | import io.opentelemetry.api.common.Attributes; 12 | import io.opentelemetry.exporter.zipkin.ZipkinSpanExporter; 13 | import io.opentelemetry.sdk.OpenTelemetrySdk; 14 | import io.opentelemetry.sdk.resources.Resource; 15 | import io.opentelemetry.sdk.trace.SdkTracerProvider; 16 | import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; 17 | import io.opentelemetry.semconv.ServiceAttributes; 18 | 19 | /** 20 | * All SDK management takes place here, away from the instrumentation code, which should only access 21 | * the OpenTelemetry APIs. 22 | */ 23 | public final class ExampleConfiguration { 24 | 25 | // Name of the service 26 | private static final String SERVICE_NAME = "myExampleService"; 27 | 28 | /** Adds a SimpleSpanProcessor initialized with ZipkinSpanExporter to the TracerSdkProvider */ 29 | static OpenTelemetry initializeOpenTelemetry(String ip, int port) { 30 | String endpoint = String.format("http://%s:%s/api/v2/spans", ip, port); 31 | ZipkinSpanExporter zipkinExporter = ZipkinSpanExporter.builder().setEndpoint(endpoint).build(); 32 | 33 | Resource serviceNameResource = 34 | Resource.create(Attributes.of(ServiceAttributes.SERVICE_NAME, SERVICE_NAME)); 35 | 36 | // Set to process the spans by the Zipkin Exporter 37 | SdkTracerProvider tracerProvider = 38 | SdkTracerProvider.builder() 39 | .addSpanProcessor(SimpleSpanProcessor.create(zipkinExporter)) 40 | .setResource(Resource.getDefault().merge(serviceNameResource)) 41 | .build(); 42 | OpenTelemetrySdk openTelemetry = 43 | OpenTelemetrySdk.builder().setTracerProvider(tracerProvider).buildAndRegisterGlobal(); 44 | 45 | // add a shutdown hook to shut down the SDK 46 | Runtime.getRuntime().addShutdownHook(new Thread(tracerProvider::close)); 47 | 48 | // return the configured instance so it can be used for instrumentation. 49 | return openTelemetry; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /zipkin/src/main/java/io/opentelemetry/example/zipkin/ZipkinExample.java: -------------------------------------------------------------------------------- 1 | package io.opentelemetry.example.zipkin; 2 | 3 | import io.opentelemetry.api.OpenTelemetry; 4 | import io.opentelemetry.api.trace.Span; 5 | import io.opentelemetry.api.trace.Tracer; 6 | import io.opentelemetry.api.trace.TracerProvider; 7 | import io.opentelemetry.context.Scope; 8 | 9 | public final class ZipkinExample { 10 | // The Tracer we'll use for the example 11 | private final Tracer tracer; 12 | 13 | public ZipkinExample(TracerProvider tracerProvider) { 14 | tracer = tracerProvider.get("io.opentelemetry.example.ZipkinExample"); 15 | } 16 | 17 | // This method instruments doWork() method 18 | public void myWonderfulUseCase() { 19 | // Generate span 20 | Span span = tracer.spanBuilder("Start my wonderful use case").startSpan(); 21 | try (Scope scope = span.makeCurrent()) { 22 | // Add some Event to the span 23 | span.addEvent("Event 0"); 24 | // execute my use case - here we simulate a wait 25 | doWork(); 26 | // Add some Event to the span 27 | span.addEvent("Event 1"); 28 | } finally { 29 | span.end(); 30 | } 31 | } 32 | 33 | public void doWork() { 34 | try { 35 | Thread.sleep(1000); 36 | } catch (InterruptedException e) { 37 | // ignore in an example 38 | } 39 | } 40 | 41 | public static void main(String[] args) { 42 | // Parsing the input 43 | if (args.length < 2) { 44 | System.out.println("Missing [hostname] [port]"); 45 | System.exit(1); 46 | } 47 | 48 | String ip = args[0]; 49 | int port = Integer.parseInt(args[1]); 50 | 51 | // it is important to initialize the OpenTelemetry SDK as early as possible in your process. 52 | OpenTelemetry openTelemetry = ExampleConfiguration.initializeOpenTelemetry(ip, port); 53 | 54 | TracerProvider tracerProvider = openTelemetry.getTracerProvider(); 55 | 56 | // start example 57 | ZipkinExample example = new ZipkinExample(tracerProvider); 58 | example.myWonderfulUseCase(); 59 | 60 | System.out.println("Bye"); 61 | } 62 | } 63 | --------------------------------------------------------------------------------