Compare commits

..

1 Commits

Author SHA1 Message Date
OpenTelemetry Bot f97bea8f12
[release/v1.47.x] Prepare release 1.47.0 (#7085) 2025-02-07 13:34:36 -06:00
671 changed files with 5894 additions and 20804 deletions

View File

@ -1,8 +0,0 @@
# see https://github.com/cncf/clomonitor/blob/main/docs/checks.md#exemptions
exemptions:
- check: artifacthub_badge
reason: "Artifact Hub doesn't support Java packages"
- check: signed_releases
reason: "Maven central releases are signed and there are no GitHub release artifacts"
- check: openssf_badge
reason: "ETOOMANYBADGES, but the work has been done: https://www.bestpractices.dev/projects/9991"

View File

@ -1,40 +0,0 @@
version: 3
targets:
only:
- type: gradle
exclude:
# these modules are not published and so consumers will not be exposed to them
- type: gradle
path: ./
target: ':api:testing-internal'
- type: gradle
path: ./
target: ':exporters:otlp:testing-internal'
- type: gradle
path: ./
target: ':integration-tests'
- type: gradle
path: ./
target: ':integration-tests:graal'
- type: gradle
path: ./
target: ':integration-tests:graal-incubating'
- type: gradle
path: ./
target: ':integration-tests:otlp'
- type: gradle
path: ./
target: ':integration-tests:tracecontext'
- type: gradle
path: ./
target: ':perf-harness'
- type: gradle
path: ./
target: ':testing-internal'
experimental:
gradle:
configurations-only:
# consumer will only be exposed to these dependencies
- runtimeClasspath

View File

@ -1,85 +1,48 @@
{
$schema: 'https://docs.renovatebot.com/renovate-schema.json',
extends: [
'config:best-practices',
'helpers:pinGitHubActionDigestsToSemver',
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:base"
],
packageRules: [
"packageRules": [
{
// this is to reduce the number of renovate PRs
matchManagers: [
'github-actions',
'dockerfile',
],
extends: [
'schedule:weekly',
],
groupName: 'weekly update',
},
{
matchPackageNames: [
'io.opentelemetry.contrib:opentelemetry-aws-xray-propagator',
'io.opentelemetry.proto:opentelemetry-proto',
'io.opentelemetry.semconv:opentelemetry-semconv-incubating',
"matchPackageNames": [
"io.opentelemetry.proto:opentelemetry-proto",
"io.opentelemetry.semconv:opentelemetry-semconv-incubating"
],
// Renovate's default behavior is only to update from unstable -> unstable if it's for the
// major.minor.patch, under the assumption that you would want to update to the stable version
// of that release instead of the unstable version for a future release
// (TODO remove once the artifacts above release stable versions)
ignoreUnstable: false,
allowedVersions: '!/\\-SNAPSHOT$/',
"ignoreUnstable": false,
"allowedVersions": "!/\\-SNAPSHOT$/"
},
{
// junit-pioneer 2+ requires Java 11+
matchPackageNames: [
'org.junit-pioneer:junit-pioneer',
],
matchUpdateTypes: [
'major',
],
enabled: false,
"matchPackageNames": ["org.junit-pioneer:junit-pioneer"],
"matchUpdateTypes": ["major"],
"enabled": false
},
{
// mockito 5+ requires Java 11+
matchUpdateTypes: [
'major',
],
enabled: false,
matchPackageNames: [
'org.mockito:{/,}**',
],
"matchPackagePrefixes": ["org.mockito:"],
"matchUpdateTypes": ["major"],
"enabled": false
},
{
// jqf-fuzz version 1.8+ requires Java 11+
matchPackageNames: [
'edu.berkeley.cs.jqf:jqf-fuzz',
],
matchUpdateTypes: [
'major',
'minor',
],
enabled: false,
"matchPackageNames": ["edu.berkeley.cs.jqf:jqf-fuzz"],
"matchUpdateTypes": ["major", "minor"],
"enabled": false
},
{
// pinned version for compatibility
matchPackageNames: [
'org.jetbrains.kotlinx:kotlinx-coroutines-core',
],
matchCurrentVersion: '1.5.2',
enabled: false,
"matchPackageNames": ["org.jetbrains.kotlinx:kotlinx-coroutines-core"],
"matchCurrentVersion": "1.5.2",
"enabled": false
},
{
groupName: 'spotless packages',
matchPackageNames: [
'com.diffplug.spotless{/,}**',
],
},
{
// equals verifier v4+ requires java 17+
groupName: 'nl.jqno.equalsverifier',
matchPackageNames: [ 'equalsverifier'],
matchUpdateTypes: [ 'major' ],
enabled: false
"matchPackagePrefixes": ["com.diffplug.spotless"],
"groupName": "spotless packages"
}
],
]
}

View File

@ -1,24 +1,75 @@
# Repository settings
This document describes any changes that have been made to the
settings in this repository outside the settings tracked in the
private admin repo.
Repository settings in addition to what's documented already at
<https://github.com/open-telemetry/community/blob/main/docs/how-to-configure-new-repository.md>.
## General > Pull Requests
* Allow squash merging > Default to pull request title
## Actions > General
* Fork pull request workflows from outside collaborators:
"Require approval for first-time contributors who are new to GitHub"
(To reduce friction for new contributors,
as the default is "Require approval for first-time contributors")
## Branch protections
The order of branch protection rules
[can be important](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests/managing-a-branch-protection-rule#about-branch-protection-rules).
The branch protection rules below should be added before the `**/**` branch protection rule
(this may require deleting the `**/**` rule and recreating it at the end).
### `main`
* Require branches to be up to date before merging: UNCHECKED
(PR jobs take too long, and leaving this unchecked has not been a significant problem)
* Status checks that are required:
* EasyCLA
* required-status-check
### `release/*`
Same settings as above for `main`, except:
* Restrict pushes that create matching branches: UNCHECKED
(So that opentelemetrybot can create release branches)
### `renovate/**/**`, and `opentelemetrybot/*`
* Require status checks to pass before merging: UNCHECKED
(So that renovate PRs can be rebased)
* Restrict who can push to matching branches: UNCHECKED
(So that bots can create PR branches in this repository)
* Allow force pushes > Everyone
(So that renovate PRs can be rebased)
* Allow deletions: CHECKED
(So that bot PR branches can be deleted)
### `benchmarks`
- Everything UNCHECKED
(This branch is currently only used for directly pushing benchmarking results from the
[overhead benchmark](https://github.com/open-telemetry/opentelemetry-java/actions/workflows/benchmark.yml)
job)
## Secrets and variables > Actions
- `GPG_PASSWORD` - stored in OpenTelemetry-Java 1Password
- `GPG_PRIVATE_KEY` - stored in OpenTelemetry-Java 1Password
- `NVD_API_KEY` - stored in OpenTelemetry-Java 1Password
- Generated at https://nvd.nist.gov/developers/request-an-api-key
- Key is associated with [@trask](https://github.com/trask)'s gmail address
- `SONATYPE_KEY` - owned by [@jack-berg](https://github.com/jack-berg)
- `SONATYPE_USER` - owned by [@jack-berg](https://github.com/jack-berg)
### Organization secrets
- `FOSSA_API_KEY`
- `OTELBOT_PRIVATE_KEY`
### Organization variables
- `OTELBOT_APP_ID`
* `GPG_PASSWORD` - stored in OpenTelemetry-Java 1Password
* `GPG_PRIVATE_KEY` - stored in OpenTelemetry-Java 1Password
* `SONATYPE_KEY` - owned by [@jack-berg](https://github.com/jack-berg)
* `SONATYPE_USER` - owned by [@jack-berg](https://github.com/jack-berg)

View File

@ -86,5 +86,5 @@ echo $contributors1 $contributors2 \
| grep -v github-actions \
| grep -v renovate \
| grep -v codecov \
| grep -v otelbot \
| grep -v opentelemetrybot \
| sed 's/^/@/'

View File

@ -1,8 +0,0 @@
#!/bin/bash -e
version=$1
versionWithSnapshot="$version-SNAPSHOT"
sed -Ei "s/[0-9]+\.[0-9]+\.[0-9]+/$version/" version.gradle.kts
sed -Ei "1 s/(Comparing source compatibility of [a-z-]+)-[0-9]+\.[0-9]+\.[0-9]+(-SNAPSHOT)?.jar/\1-$versionWithSnapshot.jar/" docs/apidiffs/current_vs_latest/*.txt

View File

@ -1,4 +1,4 @@
#!/bin/bash -e
git config user.name otelbot
git config user.email 197425009+otelbot@users.noreply.github.com
git config user.name opentelemetrybot
git config user.email 107717825+opentelemetrybot@users.noreply.github.com

View File

@ -6,13 +6,8 @@ on:
description: "The pull request # to backport"
required: true
permissions:
contents: read
jobs:
backport:
permissions:
contents: write # for git push to PR branch
runs-on: ubuntu-latest
steps:
- run: |
@ -21,7 +16,7 @@ jobs:
exit 1
fi
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@v4
with:
# history is needed to run git cherry-pick below
fetch-depth: 0
@ -29,22 +24,16 @@ jobs:
- name: Use CLA approved github bot
run: .github/scripts/use-cla-approved-github-bot.sh
- uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6
id: otelbot-token
with:
app-id: ${{ vars.OTELBOT_APP_ID }}
private-key: ${{ secrets.OTELBOT_PRIVATE_KEY }}
- name: Create pull request
env:
NUMBER: ${{ github.event.inputs.number }}
# not using secrets.GITHUB_TOKEN since pull requests from that token do not run workflows
GH_TOKEN: ${{ steps.otelbot-token.outputs.token }}
GH_TOKEN: ${{ secrets.OPENTELEMETRYBOT_GITHUB_TOKEN }}
run: |
commit=$(gh pr view $NUMBER --json mergeCommit --jq .mergeCommit.oid)
title=$(gh pr view $NUMBER --json title --jq .title)
branch="otelbot/backport-${NUMBER}-to-${GITHUB_REF_NAME//\//-}"
branch="opentelemetrybot/backport-${NUMBER}-to-${GITHUB_REF_NAME//\//-}"
git checkout -b $branch
git cherry-pick $commit

View File

@ -3,15 +3,10 @@ name: Benchmark Tags
on:
workflow_dispatch:
permissions:
contents: read
jobs:
sdk-benchmark:
permissions:
contents: write # for git push to benchmarks branch
name: Benchmark SDK
runs-on: equinix-bare-metal
runs-on: self-hosted
timeout-minutes: 10
strategy:
fail-fast: false
@ -44,19 +39,19 @@ jobs:
- v1.30.0
- v1.30.1
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@v4
with:
ref: ${{ matrix.tag-version }}
- id: setup-java
name: Set up Java for build
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17
- name: Set up gradle
uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1
uses: gradle/actions/setup-gradle@v4
- name: Run jmh
run: ./gradlew jmhJar
@ -66,7 +61,7 @@ jobs:
java -jar libs/opentelemetry-sdk-trace-*-jmh.jar -rf json SpanBenchmark SpanPipelineBenchmark ExporterBenchmark
- name: Store benchmark results
uses: benchmark-action/github-action-benchmark@d48d326b4ca9ba73ca0cd0d59f108f9e02a381c7 # v1.20.4
uses: benchmark-action/github-action-benchmark@v1
with:
tool: 'jmh'
output-file-path: sdk/trace/build/jmh-result.json

View File

@ -5,28 +5,23 @@ on:
branches: [ main ]
workflow_dispatch:
permissions:
contents: read
jobs:
sdk-benchmark:
permissions:
contents: write # for git push to benchmarks branch
name: Benchmark SDK
runs-on: equinix-bare-metal
runs-on: self-hosted
timeout-minutes: 10
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@v4
- id: setup-java
name: Set up Java for build
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17
- name: Set up gradle
uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1
uses: gradle/actions/setup-gradle@v4
- name: Run jmh
run: ./gradlew jmhJar
@ -36,7 +31,7 @@ jobs:
java -jar libs/opentelemetry-sdk-trace-*-jmh.jar -rf json SpanBenchmark SpanPipelineBenchmark ExporterBenchmark
- name: Store benchmark results
uses: benchmark-action/github-action-benchmark@d48d326b4ca9ba73ca0cd0d59f108f9e02a381c7 # v1.20.4
uses: benchmark-action/github-action-benchmark@v1
with:
tool: 'jmh'
output-file-path: sdk/trace/build/jmh-result.json

View File

@ -9,27 +9,21 @@ on:
- main
workflow_dispatch:
permissions:
contents: read
jobs:
publish:
permissions:
contents: read
packages: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@v4
- name: Login to GitHub package registry
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
uses: docker/build-push-action@v6
with:
context: integration-tests/tracecontext/docker
push: true

View File

@ -12,9 +12,6 @@ concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
cancel-in-progress: true
permissions:
contents: read
jobs:
build:
name: Build
@ -35,7 +32,7 @@ jobs:
- 23
# Collect coverage on latest LTS
include:
- os: ubuntu-latest
- os: ubuntu-20.04
test-java-version: 21
coverage: true
jmh-based-tests: true
@ -52,24 +49,24 @@ jobs:
- os: macos-13
test-java-version: 23
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@v4
- id: setup-java-test
name: Set up Java ${{ matrix.test-java-version }} for tests
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: ${{ matrix.test-java-version }}
- id: setup-java
name: Set up Java for build
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17
- name: Set up gradle
uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1
uses: gradle/actions/setup-gradle@v4
- name: Build
run: >
./gradlew build
@ -82,10 +79,10 @@ jobs:
RUN_JMH_BASED_TESTS: ${{ matrix.jmh-based-tests }}
- name: Check for diff
# The jApiCmp diff compares current to latest, which isn't appropriate for release branches
# The jApiCmp diff compares current to latest, which isn't appropriate for release branches, or for bot-generated PRs
# this fails on windows because of the bash-specific if/then/else syntax, but that's ok
# because we only need to run this validation once (on any platform)
if: ${{ matrix.os != 'windows-latest' && !startsWith(github.ref_name, 'release/') && !startsWith(github.base_ref, 'release/') }}
if: ${{ matrix.os != 'windows-latest' && !startsWith(github.ref_name, 'release/') && !startsWith(github.base_ref, 'release/') && (github.actor != 'opentelemetrybot') }}
run: |
# need to "git add" in case any generated files did not already exist
git add docs/apidiffs
@ -99,12 +96,12 @@ jobs:
exit 1
fi
- uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24 # v5.4.3
- uses: codecov/codecov-action@v5
if: ${{ matrix.coverage }}
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
- uses: actions/upload-artifact@v4
if: ${{ matrix.coverage }}
with:
name: coverage-report
@ -135,17 +132,17 @@ jobs:
needs: build
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@v4
- id: setup-java
name: Set up Java
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17
- name: Set up gradle
uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1
uses: gradle/actions/setup-gradle@v4
# skipping release branches because the versions in those branches are not snapshots
# (also this skips pull requests)
if: ${{ github.ref_name == 'main' && github.repository == 'open-telemetry/opentelemetry-java' }}
@ -161,19 +158,13 @@ jobs:
GPG_PASSWORD: ${{ secrets.GPG_PASSWORD }}
build-graal:
name: Build GraalVM
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
test-graal-version:
- 21
- 23
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: graalvm/setup-graalvm@7f488cf82a3629ee755e4e97342c01d6bed318fa # v1.3.5
- uses: actions/checkout@v4
- uses: graalvm/setup-graalvm@v1
with:
java-version: ${{ matrix.test-graal-version }}
# TODO(jack-berg): Which versions do we need to test? Should we use a matrix scheme?
java-version: '21'
distribution: 'graalvm'
components: 'native-image'
github-token: ${{ secrets.GITHUB_TOKEN }}

44
.github/workflows/codeql-daily.yml vendored Normal file
View File

@ -0,0 +1,44 @@
name: CodeQL (daily)
on:
schedule:
# Daily at 01:30 (UTC)
- cron: '30 1 * * *'
workflow_dispatch:
jobs:
analyze:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Java 17
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: java
# using "latest" helps to keep up with the latest Kotlin support
# see https://github.com/github/codeql-action/issues/1555#issuecomment-1452228433
tools: latest
- name: Set up gradle
uses: gradle/actions/setup-gradle@v4
- name: Assemble
# skipping build cache is needed so that all modules will be analyzed
run: ./gradlew assemble --no-build-cache
- name: Perform CodeQL analysis
uses: github/codeql-action/analyze@v3
open-issue-on-failure:
# open an issue on failure because it can be easy to miss CI failure notifications
needs:
- analyze
if: failure() && github.run_attempt == 1
uses: ./.github/workflows/reusable-open-issue-on-failure.yml

View File

@ -1,65 +0,0 @@
name: CodeQL
on:
pull_request:
branches:
- main
- release/*
- benchmarks
push:
branches:
- main
- release/*
- benchmarks
schedule:
- cron: "23 16 * * 2" # weekly at 16:23 UTC on Tuesday
permissions:
contents: read
jobs:
analyze:
permissions:
contents: read
actions: read # for github/codeql-action/init to get workflow details
security-events: write # for github/codeql-action/analyze to upload SARIF results
strategy:
fail-fast: false
matrix:
include:
- language: actions
- language: java
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Set up Java 17
if: matrix.language == 'java'
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
with:
distribution: temurin
java-version: 17
- name: Set up gradle
if: matrix.language == 'java'
uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1
- name: Initialize CodeQL
uses: github/codeql-action/init@4e828ff8d448a8a6e532957b1811f387a63867e8 # v3.29.4
with:
languages: ${{ matrix.language }}
# using "latest" helps to keep up with the latest Kotlin support
# see https://github.com/github/codeql-action/issues/1555#issuecomment-1452228433
tools: latest
- name: Assemble
if: matrix.language == 'java'
# --no-build-cache is required for codeql to analyze all modules
# --no-daemon is required for codeql to observe the compilation
# (see https://docs.github.com/en/code-security/codeql-cli/getting-started-with-the-codeql-cli/preparing-your-code-for-codeql-analysis#specifying-build-commands)
run: ./gradlew assemble --no-build-cache --no-daemon
- name: Perform CodeQL analysis
uses: github/codeql-action/analyze@4e828ff8d448a8a6e532957b1811f387a63867e8 # v3.29.4
with:
category: "/language:${{matrix.language}}"

View File

@ -5,14 +5,8 @@ on:
- cron: "23 3 * * *"
workflow_dispatch:
permissions:
contents: read
jobs:
copy-images:
permissions:
contents: read
packages: write
strategy:
matrix:
include:
@ -27,7 +21,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Docker login
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}

View File

@ -1,20 +0,0 @@
name: FOSSA
on:
push:
branches:
- main
permissions:
contents: read
jobs:
fossa:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: fossas/fossa-action@3ebcea1862c6ffbd5cf1b4d0bd6b3fe7bd6f2cac # v1.7.0
with:
api-key: ${{secrets.FOSSA_API_KEY}}
team: OpenTelemetry

View File

@ -0,0 +1,69 @@
name: Generate Post-Release PR
on:
workflow_dispatch:
jobs:
prereqs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Verify prerequisites
run: |
if [[ $GITHUB_REF_NAME != main ]]; then
echo this workflow should only be run against main
exit 1
fi
create-pull-request-against-main:
runs-on: ubuntu-latest
needs:
- prereqs
steps:
- uses: actions/checkout@v4
- id: setup-java
name: Set up Java for build
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17
- name: Set environment variables
run: |
version=$(.github/scripts/get-version.sh)
echo "VERSION=$version" >> $GITHUB_ENV
prior_version=$(.github/scripts/get-prior-version.sh)
echo "PRIOR_VERSION=$prior_version" >> $GITHUB_ENV
if [[ $prior_version =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then
major="${BASH_REMATCH[1]}"
minor="${BASH_REMATCH[2]}"
patch="${BASH_REMATCH[3]}"
two_releases_ago="$major.$((minor - 1)).$patch"
else
echo "unexpected prior version: $prior_version"
exit 1
fi
echo "TWO_VERSIONS_AGO=$two_releases_ago" >> $GITHUB_ENV
- name: Use CLA approved github bot
run: .github/scripts/use-cla-approved-github-bot.sh
- name: Create pull request against main
env:
# not using secrets.GITHUB_TOKEN since pull requests from that token do not run workflows
GH_TOKEN: ${{ secrets.OPENTELEMETRYBOT_GITHUB_TOKEN }}
run: |
./gradlew updateVersionInDocs -Prelease.version=$PRIOR_VERSION
./gradlew japicmp -PapiBaseVersion=$TWO_VERSIONS_AGO -PapiNewVersion=$PRIOR_VERSION
./gradlew --refresh-dependencies japicmp
message="Post release for version $PRIOR_VERSION"
body="Post-release updates for version \`$PRIOR_VERSION\`."
branch="opentelemetrybot/post-release-for-${PRIOR_VERSION}"
git checkout -b $branch
git add docs/apidiffs
git commit -a -m "$message"
git push --set-upstream origin $branch
gh pr create --title "$message" \
--body "$body" \
--base main

View File

@ -1,16 +1,16 @@
name: Gradle wrapper validation
on:
push:
pull_request:
permissions:
contents: read
paths:
- '**/gradle/wrapper/**'
push:
paths:
- '**/gradle/wrapper/**'
jobs:
gradle-wrapper-validation:
validation:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@v4
- uses: gradle/actions/wrapper-validation@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1
- uses: gradle/actions/wrapper-validation@v4.3.0

View File

@ -4,21 +4,14 @@ on:
issue_comment:
types: [created]
permissions:
contents: read
jobs:
issue_comment:
permissions:
contents: read
issues: write
pull-requests: write
if: >
contains(github.event.issue.labels.*.name, 'needs author feedback') &&
github.event.comment.user.login == github.event.issue.user.login
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@v4
- name: Remove label
env:

View File

@ -5,18 +5,11 @@ on:
# hourly at minute 23
- cron: "23 * * * *"
permissions:
contents: read
jobs:
stale:
permissions:
contents: read
issues: write # for actions/stale to close stale issues
pull-requests: write # for actions/stale to close stale PRs
runs-on: ubuntu-latest
steps:
- uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 # v9.1.0
- uses: actions/stale@v9
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
days-before-stale: 7

View File

@ -1,26 +0,0 @@
name: Javadoc.io site crawler (daily)
on:
schedule:
- cron: "30 1 * * *" # daily at 1:30 UTC
workflow_dispatch:
permissions:
contents: read
jobs:
crawl:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
with:
distribution: temurin
java-version: 17
- name: Set up gradle
uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1
- name: Run crawler
run: ./gradlew :javadoc-crawler:crawl

View File

@ -23,7 +23,7 @@ jobs:
with:
persist-credentials: false
- uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2
- uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0
with:
results_file: results.sarif
results_format: sarif
@ -33,7 +33,7 @@ jobs:
# uploads of run results in SARIF format to the repository Actions tab.
# https://docs.github.com/en/actions/advanced-guides/storing-workflow-data-as-artifacts
- name: "Upload artifact"
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
with:
name: SARIF file
path: results.sarif
@ -42,6 +42,6 @@ jobs:
# Upload the results to GitHub's code scanning dashboard (optional).
# Commenting out will disable upload of results to your repo's Code Scanning dashboard
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@4e828ff8d448a8a6e532957b1811f387a63867e8 # v3.29.4
uses: github/codeql-action/upload-sarif@dd746615b3b9d728a6a37ca2045b68ca76d4841a # v3.28.8
with:
sarif_file: results.sarif

View File

@ -4,44 +4,28 @@ name: OWASP dependency check (daily)
on:
schedule:
- cron: "30 1 * * *" # daily at 1:30 UTC
- cron: '30 1 * * *'
workflow_dispatch:
permissions:
contents: read
jobs:
analyze:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17
- name: Set up gradle
uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1
uses: gradle/actions/setup-gradle@v4
- name: Check dependencies
run: ./gradlew dependencyCheckAnalyze
env:
NVD_API_KEY: ${{ secrets.NVD_API_KEY }}
- name: Upload report
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
uses: actions/upload-artifact@v4
with:
path: javaagent/build/reports
workflow-notification:
permissions:
contents: read
issues: write
needs:
- analyze
if: always()
uses: ./.github/workflows/reusable-workflow-notification.yml
with:
success: ${{ needs.analyze.result == 'success' }}

View File

@ -2,16 +2,11 @@ name: Prepare patch release
on:
workflow_dispatch:
permissions:
contents: read
jobs:
prepare-patch-release:
permissions:
contents: write # for git push to PR branch
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@v4
- run: |
if [[ ! $GITHUB_REF_NAME =~ ^release/v[0-9]+\.[0-9]+\.x$ ]]; then
@ -37,7 +32,7 @@ jobs:
echo "VERSION=$major_minor.$((patch + 1))" >> $GITHUB_ENV
- name: Update version
run: .github/scripts/update-version.sh $VERSION
run: sed -Ei "s/[0-9]+\.[0-9]+\.[0-9]+/$VERSION/" version.gradle.kts
- name: Update the change log with the approximate release date
run: |
@ -47,19 +42,13 @@ jobs:
- name: Use CLA approved github bot
run: .github/scripts/use-cla-approved-github-bot.sh
- uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6
id: otelbot-token
with:
app-id: ${{ vars.OTELBOT_APP_ID }}
private-key: ${{ secrets.OTELBOT_PRIVATE_KEY }}
- name: Create pull request
env:
# not using secrets.GITHUB_TOKEN since pull requests from that token do not run workflows
GH_TOKEN: ${{ steps.otelbot-token.outputs.token }}
GH_TOKEN: ${{ secrets.OPENTELEMETRYBOT_GITHUB_TOKEN }}
run: |
message="Prepare release $VERSION"
branch="otelbot/prepare-release-${VERSION}"
branch="opentelemetrybot/prepare-release-${VERSION}"
git checkout -b $branch
git commit -a -m "$message"

View File

@ -2,14 +2,11 @@ name: Prepare release branch
on:
workflow_dispatch:
permissions:
contents: read
jobs:
prereqs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@v4
- name: Verify prerequisites
run: |
@ -24,13 +21,11 @@ jobs:
fi
create-pull-request-against-release-branch:
permissions:
contents: write # for git push to PR branch
runs-on: ubuntu-latest
needs:
- prereqs
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@v4
- name: Create release branch
run: |
@ -59,19 +54,13 @@ jobs:
- name: Use CLA approved github bot
run: .github/scripts/use-cla-approved-github-bot.sh
- uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6
id: otelbot-token
with:
app-id: ${{ vars.OTELBOT_APP_ID }}
private-key: ${{ secrets.OTELBOT_PRIVATE_KEY }}
- name: Create pull request against the release branch
env:
# not using secrets.GITHUB_TOKEN since pull requests from that token do not run workflows
GH_TOKEN: ${{ steps.otelbot-token.outputs.token }}
GH_TOKEN: ${{ secrets.OPENTELEMETRYBOT_GITHUB_TOKEN }}
run: |
message="Prepare release $VERSION"
branch="otelbot/prepare-release-${VERSION}"
branch="opentelemetrybot/prepare-release-${VERSION}"
git checkout -b $branch
git commit -a -m "$message"
@ -81,13 +70,11 @@ jobs:
--base $RELEASE_BRANCH_NAME
create-pull-request-against-main:
permissions:
contents: write # for git push to PR branch
runs-on: ubuntu-latest
needs:
- prereqs
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@v4
- name: Set environment variables
run: |
@ -100,11 +87,11 @@ jobs:
echo "unexpected version: $version"
exit 1
fi
echo "NEXT_VERSION=${next_version}" >> $GITHUB_ENV
echo "NEXT_VERSION=$next_version" >> $GITHUB_ENV
echo "VERSION=$version" >> $GITHUB_ENV
- name: Update version
run: .github/scripts/update-version.sh $NEXT_VERSION
run: sed -Ei "s/[0-9]+\.[0-9]+\.[0-9]+/$NEXT_VERSION/" version.gradle.kts
- name: Update the change log on main
run: |
@ -115,20 +102,14 @@ jobs:
- name: Use CLA approved github bot
run: .github/scripts/use-cla-approved-github-bot.sh
- uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6
id: otelbot-token
with:
app-id: ${{ vars.OTELBOT_APP_ID }}
private-key: ${{ secrets.OTELBOT_PRIVATE_KEY }}
- name: Create pull request against main
env:
# not using secrets.GITHUB_TOKEN since pull requests from that token do not run workflows
GH_TOKEN: ${{ steps.otelbot-token.outputs.token }}
GH_TOKEN: ${{ secrets.OPENTELEMETRYBOT_GITHUB_TOKEN }}
run: |
message="Update version to $NEXT_VERSION"
body="Update version to \`$NEXT_VERSION\`."
branch="otelbot/update-version-to-${NEXT_VERSION}"
branch="opentelemetrybot/update-version-to-${NEXT_VERSION}"
git checkout -b $branch
git commit -a -m "$message"

View File

@ -2,17 +2,11 @@ name: Release
on:
workflow_dispatch:
permissions:
contents: read
jobs:
release:
permissions:
contents: write # for creating the release
runs-on: ubuntu-24.04
outputs:
version: ${{ steps.create-github-release.outputs.version }}
prior-version: ${{ steps.create-github-release.outputs.prior-version }}
steps:
- run: |
if [[ $GITHUB_REF_NAME != release/* ]]; then
@ -20,15 +14,15 @@ jobs:
exit 1
fi
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@v4
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17
- name: Set up gradle
uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1
uses: gradle/actions/setup-gradle@v4
- name: Build and publish artifacts
run: ./gradlew assemble publishToSonatype closeAndReleaseSonatypeStagingRepository
@ -65,7 +59,7 @@ jobs:
# check out main branch to verify there won't be problems with merging the change log
# at the end of this workflow
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@v4
with:
ref: main
@ -80,7 +74,7 @@ jobs:
fi
# back to the release branch
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@v4
with:
# tags are needed for the generate-release-contributors.sh script
fetch-depth: 0
@ -129,20 +123,14 @@ jobs:
--notes-file /tmp/release-notes.txt \
v$VERSION
# these are used as job outputs
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "prior-version=$PRIOR_VERSION" >> $GITHUB_OUTPUT
update-apidiff-baseline-and-docs-to-released-version:
permissions:
contents: write # for git push to PR branch
merge-change-log-to-main:
runs-on: ubuntu-latest
needs:
- release
steps:
# add change log sync (if any) into this PR since the apidiff update
# is required before any other PR can be merged anyway
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@v4
- name: Copy change log section from release branch
env:
@ -151,7 +139,7 @@ jobs:
sed -n "0,/^## Version $VERSION /d;/^## Version /q;p" CHANGELOG.md \
> /tmp/changelog-section.md
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@v4
with:
ref: main
@ -162,59 +150,32 @@ jobs:
run: |
release_date=$(gh release view v$VERSION --json publishedAt --jq .publishedAt | sed 's/T.*//')
RELEASE_DATE=$release_date .github/scripts/merge-change-log-after-release.sh
git add CHANGELOG.md
- name: Wait for release to be available in maven central
env:
VERSION: ${{ needs.release.outputs.version }}
run: |
until curl --silent \
--show-error \
--output /dev/null \
--head \
--fail \
https://repo1.maven.org/maven2/io/opentelemetry/opentelemetry-api/$VERSION/opentelemetry-api-$VERSION.jar
do
sleep 60
done
- name: Update apidiff baseline
env:
VERSION: ${{ needs.release.outputs.version }}
PRIOR_VERSION: ${{ needs.release.outputs.prior-version }}
run: |
./gradlew japicmp -PapiBaseVersion=$PRIOR_VERSION -PapiNewVersion=$VERSION
./gradlew --refresh-dependencies japicmp
git add docs/apidiffs
- name: Update versions in README.md
env:
VERSION: ${{ needs.release.outputs.version }}
run: |
./gradlew updateVersionInDocs -Prelease.version=$VERSION
git add README.md
- name: Use CLA approved bot
- name: Use CLA approved github bot
run: .github/scripts/use-cla-approved-github-bot.sh
- uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6
id: otelbot-token
with:
app-id: ${{ vars.OTELBOT_APP_ID }}
private-key: ${{ secrets.OTELBOT_PRIVATE_KEY }}
- name: Create pull request against main
env:
VERSION: ${{ needs.release.outputs.version }}
# not using secrets.GITHUB_TOKEN since pull requests from that token do not run workflows
GH_TOKEN: ${{ steps.otelbot-token.outputs.token }}
GH_TOKEN: ${{ secrets.OPENTELEMETRYBOT_GITHUB_TOKEN }}
run: |
message="Update apidiff baseline and documentation versions to released version $VERSION"
body="Update apidiff baseline and documentation versions to released version \`$VERSION\`."
branch="otelbot/update-apidiff-baseline-and-documentation-to-released-version-${VERSION}"
if git diff --quiet; then
if [[ $VERSION =~ ^[0-9]+\.[0-9]+\.0 ]]; then
echo there are no updates to merge, not creating pull request
exit 0 # success
else
echo patch release notes did not get applied for some reason
exit 1 # failure
fi
fi
message="Merge change log updates from $GITHUB_REF_NAME"
body="Merge log updates from \`$GITHUB_REF_NAME\`."
branch="opentelemetrybot/merge-change-log-updates-from-${GITHUB_REF_NAME//\//-}"
git checkout -b $branch
git commit -m "$message"
git commit -a -m "$message"
git push --set-upstream origin $branch
gh pr create --title "$message" \
--body "$body" \

View File

@ -3,22 +3,17 @@ name: Reusable - Markdown link check
on:
workflow_call:
permissions:
contents: read
jobs:
markdown-link-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@v4
- uses: lycheeverse/lychee-action@82202e5e9c2f4ef1a55a3d02563e1cb6041e5332 # v2.4.1
- uses: lycheeverse/lychee-action@v2
with:
# excluding links to pull requests and issues is done for performance
args: >
--include-fragments
--exclude "^https://github.com/open-telemetry/opentelemetry-java/(issues|pull)/\\d+$"
--exclude "^https://github.com/open-telemetry/opentelemetry-java/(issue|pull)/\\d+$"
--max-retries 6
--retry-wait-time 10
--max-concurrency 1
.

View File

@ -3,14 +3,11 @@ name: Reusable - Misspell check
on:
workflow_call:
permissions:
contents: read
jobs:
misspell-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@v4
- name: Install misspell
run: |

View File

@ -3,17 +3,11 @@ name: Reusable - Open issue on workflow failure
on:
workflow_call:
permissions:
contents: read
jobs:
open-issue:
permissions:
contents: read
issues: write # for creating the issue
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@v4
- name: Open issue
env:

View File

@ -1,44 +0,0 @@
# this is useful because notifications for scheduled workflows are only sent to the user who
# initially created the given workflow
name: Reusable - Workflow notification
on:
workflow_call:
inputs:
success:
type: boolean
required: true
permissions:
contents: read
jobs:
workflow-notification:
permissions:
contents: read
issues: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Open issue or add comment if issue already open
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# TODO (trask) search doesn't support exact phrases, so it's possible that this could grab the wrong issue
number=$(gh issue list --search "in:title Workflow failed: $GITHUB_WORKFLOW" --limit 1 --json number -q .[].number)
echo $number
echo ${{ inputs.success }}
if [[ $number ]]; then
if [[ "${{ inputs.success }}" == "true" ]]; then
gh issue close $number
else
gh issue comment $number \
--body "See [$GITHUB_WORKFLOW #$GITHUB_RUN_NUMBER](https://github.com/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID)."
fi
elif [[ "${{ inputs.success }}" == "false" ]]; then
gh issue create --title "Workflow failed: $GITHUB_WORKFLOW (#$GITHUB_RUN_NUMBER)" \
--body "See [$GITHUB_WORKFLOW #$GITHUB_RUN_NUMBER](https://github.com/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID)."
fi

View File

@ -1,239 +1,5 @@
# Changelog
## Unreleased
## Version 1.52.0 (2025-07-11)
### API
#### Common
* Promote `ComponentLoader` to new `opentelemetry-common` artifact,
standardize SPI loading
([#7446](https://github.com/open-telemetry/opentelemetry-java/pull/7446))
#### Context
* LazyStorage passes its ClassLoader when loading ContextStorageProvider SPI
([#7424](https://github.com/open-telemetry/opentelemetry-java/pull/7424))
#### Incubator
* Add context and severity params to ExtendedLogger#isEnabled
([#7268](https://github.com/open-telemetry/opentelemetry-java/pull/7268))
* Add new convenience methods for converting DeclarativeConfigProperties to config model
([#7453](https://github.com/open-telemetry/opentelemetry-java/pull/7453))
### SDK
* Add custom stacktrace renderer which is length limit aware
([#7281](https://github.com/open-telemetry/opentelemetry-java/pull/7281))
#### Metrics
* Propagate flush to PeriodicMetricReader's metricExporter.
([#7410](https://github.com/open-telemetry/opentelemetry-java/pull/7410))
#### Exporters
* OTLP - JdkHttpSender: ensure proper closure of HttpClient in shutdown method
([#7390](https://github.com/open-telemetry/opentelemetry-java/pull/7390))
* OTLP: profile exporters fix and test improvements
([#7442](https://github.com/open-telemetry/opentelemetry-java/pull/7442))
* OTLP: Loading Compressor SPI via ComponentLoader configured through setComponentLoader
([#7428](https://github.com/open-telemetry/opentelemetry-java/pull/7428))
* Prometheus: add scope schema URL and attributes
([#7356](https://github.com/open-telemetry/opentelemetry-java/pull/7356))
* Prometheus: extend prometheus declarative config support to include without_scope_info,
with_resource_constant_labels
([#6840](https://github.com/open-telemetry/opentelemetry-java/pull/6840))
#### Extensions
* Autoconfigure: fix race condition of `GlobalOpenTelemetry` initialization with
`AutoConfiguredOpenTelemetrySdkBuilder`
([#7365](https://github.com/open-telemetry/opentelemetry-java/pull/7365))
* Declarative config: update to declarative config 1.0-rc.1
([#7436](https://github.com/open-telemetry/opentelemetry-java/pull/7436))
* Declarative config: resolve environment variable substitution for mixed quotes
([#7433](https://github.com/open-telemetry/opentelemetry-java/pull/7433))
## Version 1.51.0 (2025-06-06)
### API
#### Context
* Fix context storage provider property name in log message
([#7342](https://github.com/open-telemetry/opentelemetry-java/pull/7342))
### SDK
* Experimental configurable exception.* attribute resolution for SdkTracerProvider,
SdkLoggerProvider
([#7266](https://github.com/open-telemetry/opentelemetry-java/pull/7266))
#### Exporters
* All exporters: implement new SemConv exporter health metrics, with configuration API for selecting
schema version
([#7265](https://github.com/open-telemetry/opentelemetry-java/pull/7265))
* OTLP: Add gRPC export for profiles signal type.
([#7301](https://github.com/open-telemetry/opentelemetry-java/pull/7301))
* OTLP: Run JDK HTTP sender on non-daemon threads.
([#7322](https://github.com/open-telemetry/opentelemetry-java/pull/7322))
* Prometheus: fix serialization of arrays
([#7291](https://github.com/open-telemetry/opentelemetry-java/pull/7291))
* OTLP: exporter tolerates instances of LogRecordData when incubator is present
([#7393](https://github.com/open-telemetry/opentelemetry-java/pull/7393))
#### Extensions
* Declarative config: Handle instrumentation node changes in yaml config file format 0.4
([#7357](https://github.com/open-telemetry/opentelemetry-java/pull/7357))
## Version 1.50.0 (2025-05-09)
### API
* Clarify that AttributesBuilder.put allows nulls
([#7271](https://github.com/open-telemetry/opentelemetry-java/pull/7271))
* Stabilize log record event name
([#7277](https://github.com/open-telemetry/opentelemetry-java/pull/7277))
#### Context
* Fix duplicated ExecutorService wrap
([#7245](https://github.com/open-telemetry/opentelemetry-java/pull/7245))
* Promote getAll to TextMapGetter stable API
([#7267](https://github.com/open-telemetry/opentelemetry-java/pull/7267))
#### Incubator
* Add ExtendedLogRecordBuilder#setException
([#7182](https://github.com/open-telemetry/opentelemetry-java/pull/7182))
* Add experimental support for log extended attributes
([#7123](https://github.com/open-telemetry/opentelemetry-java/pull/7123))
### SDK
* Remove Java9VersionSpecific clock implementation
([#7221](https://github.com/open-telemetry/opentelemetry-java/pull/7221))
* Add addProcessorFirst to SdkTracerProviderBuilder, SdkLoggerProviderBuilder
([#7243](https://github.com/open-telemetry/opentelemetry-java/pull/7243))
#### Logs
* Add `setLoggerConfigurator` support to `LoggerProvider`
([#7332](https://github.com/open-telemetry/opentelemetry-java/pull/7332))
#### Metrics
* Add DelegatingMetricData
([#7229](https://github.com/open-telemetry/opentelemetry-java/pull/7229))
* Spatial aggregation for async instruments with filtering views
([#7264](https://github.com/open-telemetry/opentelemetry-java/pull/7264))
#### Exporters
* Prometheus: Add Authenticator support for PrometheusHttpServer
([#7225](https://github.com/open-telemetry/opentelemetry-java/pull/7225))
* OTLP: Fix OTLP metric exporter toBuilder() loosing temporality
([#7280](https://github.com/open-telemetry/opentelemetry-java/pull/7280))
* OTLP: Allow Otlp*MetricExporter's to publish export stats
([#7255](https://github.com/open-telemetry/opentelemetry-java/pull/7255))
#### Extensions
* Declarative config: Add support for escaping env var substitution
([#7033](https://github.com/open-telemetry/opentelemetry-java/pull/7033))
* Declarative config: update to opentelemetry-configuration 0.4
([#7064](https://github.com/open-telemetry/opentelemetry-java/pull/7064))
* Declarativeconfig: Refactor internals to add DeclarativeConfigContext
([#7293](https://github.com/open-telemetry/opentelemetry-java/pull/7293))
### Project tooling
* Kotlin extension: Update min kotlin version to 1.8
([#7155](https://github.com/open-telemetry/opentelemetry-java/pull/7155))
* Add javadoc site crawler
([#7300](https://github.com/open-telemetry/opentelemetry-java/pull/7300),
[#7316](https://github.com/open-telemetry/opentelemetry-java/pull/7316))
## Version 1.49.0 (2025-04-04)
### SDK
#### Trace
* Avoid linear queue.size() calls in span producers by storing queue size separately
([#7141](https://github.com/open-telemetry/opentelemetry-java/pull/7141))
#### Exporters
* OTLP: Add support for setting exporter executor service
([#7152](https://github.com/open-telemetry/opentelemetry-java/pull/7152))
* OTLP: Refine delay jitter for exponential backoff
([#7206](https://github.com/open-telemetry/opentelemetry-java/pull/7206))
#### Extensions
* Autoconfigure: Remove support for otel.experimental.exporter.otlp.retry.enabled
([#7200](https://github.com/open-telemetry/opentelemetry-java/pull/7200))
* Autoconfigure: Add stable cardinality limit property otel.java.metrics.cardinality.limit
([#7199](https://github.com/open-telemetry/opentelemetry-java/pull/7199))
* Incubator: Add declarative config model customizer SPI
([#7118](https://github.com/open-telemetry/opentelemetry-java/pull/7118))
## Version 1.48.0 (2025-03-07)
### API
* Add some helpful logging attribute methods to `LogRecordBuilder`
([#7089](https://github.com/open-telemetry/opentelemetry-java/pull/7089))
#### Incubator
* Introduce ConfigProvider API. Rename `StructuredConfigProperties` to `DeclarativeConfigProperties`
and move to `opentelemetry-api-incubator`. Rename `FileConfiguration`
to `DeclarativeConfiguration`.
([#6549](https://github.com/open-telemetry/opentelemetry-java/pull/6549))
### SDK
* Log warning and adjust when BatchLogRecordProcessor, BatchSpanProcessor `maxExportBatchSize`
exceeds `maxQueueSize`.
([#7045](https://github.com/open-telemetry/opentelemetry-java/pull/7045),
[#7148](https://github.com/open-telemetry/opentelemetry-java/pull/7148))
* Fix bug causing `ThrottlingLogger` to log more than once per minute
([#7156](https://github.com/open-telemetry/opentelemetry-java/pull/7156))
#### Metrics
* Remove obsolete `SdkMeterProviderUtil#setCardinalitylimit` API
([#7169](https://github.com/open-telemetry/opentelemetry-java/pull/7169))
#### Traces
* Fix bug preventing accurate reporting of span event dropped attribute count
([#7142](https://github.com/open-telemetry/opentelemetry-java/pull/7142))
#### Exporters
* OTLP: remove support for `otel.java.experimental.exporter.memory_mode`
which was previously replaced by `otel.java.exporter.memory_mode`
([#7127](https://github.com/open-telemetry/opentelemetry-java/pull/7127))
* OTLP: Extract sender parameters to config carrier class
(incubating API)
([#7151](https://github.com/open-telemetry/opentelemetry-java/pull/7151))
* OTLP: Add support for setting OTLP exporter service class loader
([#7150](https://github.com/open-telemetry/opentelemetry-java/pull/7150))
### Tooling
* Update android animalsniffer min API version to 23
([#7153](https://github.com/open-telemetry/opentelemetry-java/pull/7153))
## Version 1.47.0 (2025-02-07)
### API
@ -1970,7 +1736,7 @@ This release is a notable release for metrics:
* Autoconfigure performs percent decoding on `otel.resource.attributes` values.
[(#4653)](https://github.com/open-telemetry/opentelemetry-java/issues/4653)
* Unify compression configuration for exporters including
[(#4775)](https://github.com/open-telemetry/opentelemetry-java/pull/4775):
[(#4775)](https://github.com/open-telemetry/opentelemetry-java/issues/4775):
* Fix handling of `none` in OTLP exporters.
* Add `JaegerGrpcSpanExporterBuilder#setCompression(String)`.
* Add `ZipkinSpanExporterBuilder#setCompression(String)`.

112
README.md
View File

@ -1,10 +1,7 @@
# OpenTelemetry Java
[![Maven Central][maven-image]][maven-url]
[![Continuous Build][ci-image]][ci-url]
[![Coverage Status][codecov-image]][codecov-url]
[![FOSSA License Status](https://app.fossa.com/api/projects/custom%2B162%2Fgithub.com%2Fopen-telemetry%2Fopentelemetry-java.svg?type=shield&issueType=license)](https://app.fossa.com/projects/custom%2B162%2Fgithub.com%2Fopen-telemetry%2Fopentelemetry-java?ref=badge_shield&issueType=license)
[![FOSSA Security Status](https://app.fossa.com/api/projects/custom%2B162%2Fgithub.com%2Fopen-telemetry%2Fopentelemetry-java.svg?type=shield&issueType=security)](https://app.fossa.com/projects/custom%2B162%2Fgithub.com%2Fopen-telemetry%2Fopentelemetry-java?ref=badge_shield&issueType=security)
[![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/open-telemetry/opentelemetry-java/badge)](https://scorecard.dev/viewer/?uri=github.com/open-telemetry/opentelemetry-java)
[![Maven Central][maven-image]][maven-url]
[![Reproducible Builds](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/jvm-repo-rebuild/reproducible-central/master/content/io/opentelemetry/java/badge.json)](https://github.com/jvm-repo-rebuild/reproducible-central/blob/master/content/io/opentelemetry/java/README.md)
`opentelemetry-java` is the home of the Java implementation of the OpenTelemetry API for recording
@ -57,8 +54,8 @@ A bill of materials (or BOM) helps sync dependency versions of related artifacts
| Component | Description | Artifact ID | Version | Javadoc |
|----------------------------------------------|----------------------------------------|---------------------------|-------------------------------------------------------------|---------|
| [Bill of Materials (BOM)](./bom) | Bill of materials for stable artifacts | `opentelemetry-bom` | <!--VERSION_STABLE-->1.52.0<!--/VERSION_STABLE--> | N/A |
| [Alpha Bill of Materials (BOM)](./bom-alpha) | Bill of materials for alpha artifacts | `opentelemetry-bom-alpha` | <!--VERSION_UNSTABLE-->1.52.0-alpha<!--/VERSION_UNSTABLE--> | N/A |
| [Bill of Materials (BOM)](./bom) | Bill of materials for stable artifacts | `opentelemetry-bom` | <!--VERSION_STABLE-->1.46.0<!--/VERSION_STABLE--> | N/A |
| [Alpha Bill of Materials (BOM)](./bom-alpha) | Bill of materials for alpha artifacts | `opentelemetry-bom-alpha` | <!--VERSION_UNSTABLE-->1.46.0-alpha<!--/VERSION_UNSTABLE--> | N/A |
</details>
<details open>
@ -68,10 +65,9 @@ The OpenTelemetry API for recording telemetry.
| Component | Description | Artifact ID | Version | Javadoc |
|-----------------------------------|--------------------------------------------------------------------------------------|-------------------------------|-------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [API](./api/all) | OpenTelemetry API, including metrics, traces, baggage, context | `opentelemetry-api` | <!--VERSION_STABLE-->1.52.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-api.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api) |
| [API Incubator](./api/incubator) | API incubator, including pass through propagator, and extended tracer, and Event API | `opentelemetry-api-incubator` | <!--VERSION_UNSTABLE-->1.52.0-alpha<!--/VERSION_UNSTABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-api-incubator.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api-incubator) |
| [Context API](./context) | OpenTelemetry context API | `opentelemetry-context` | <!--VERSION_STABLE-->1.52.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-context.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-context) |
| [Common](./common) | Common utility methods used across API components | `opentelemetry-common` | <!--VERSION_STABLE-->1.52.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-common.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-common) |
| [API](./api/all) | OpenTelemetry API, including metrics, traces, baggage, context | `opentelemetry-api` | <!--VERSION_STABLE-->1.46.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-api.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api) |
| [API Incubator](./api/incubator) | API incubator, including pass through propagator, and extended tracer, and Event API | `opentelemetry-api-incubator` | <!--VERSION_UNSTABLE-->1.46.0-alpha<!--/VERSION_UNSTABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-api-incubator.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api-incubator) |
| [Context API](./context) | OpenTelemetry context API | `opentelemetry-context` | <!--VERSION_STABLE-->1.46.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-context.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-context) |
</details>
<details>
@ -81,8 +77,8 @@ Extensions to the OpenTelemetry API.
| Component | Description | Artifact ID | Version | Javadoc |
|---------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------|-------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [Kotlin Extension](./extensions/kotlin) | Context extension for coroutines | `opentelemetry-extension-kotlin` | <!--VERSION_STABLE-->1.52.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-extension-kotlin.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-extension-kotlin) |
| [Trace Propagators Extension](./extensions/trace-propagators) | Trace propagators, including B3, Jaeger, OT Trace | `opentelemetry-extension-trace-propagators` | <!--VERSION_STABLE-->1.52.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-extension-trace-propagators.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-extension-trace-propagators) |
| [Kotlin Extension](./extensions/kotlin) | Context extension for coroutines | `opentelemetry-extension-kotlin` | <!--VERSION_STABLE-->1.46.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-extension-kotlin.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-extension-kotlin) |
| [Trace Propagators Extension](./extensions/trace-propagators) | Trace propagators, including B3, Jaeger, OT Trace | `opentelemetry-extension-trace-propagators` | <!--VERSION_STABLE-->1.46.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-extension-trace-propagators.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-extension-trace-propagators) |
</details>
<details open>
@ -92,12 +88,12 @@ The OpenTelemetry SDK for managing telemetry producing by the API.
| Component | Description | Artifact ID | Version | Javadoc |
|------------------------------|--------------------------------------------------------|-----------------------------|---------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [SDK](./sdk/all) | OpenTelemetry SDK, including metrics, traces, and logs | `opentelemetry-sdk` | <!--VERSION_STABLE-->1.52.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-sdk.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-sdk) |
| [Metrics SDK](./sdk/metrics) | OpenTelemetry metrics SDK | `opentelemetry-sdk-metrics` | <!--VERSION_STABLE-->1.52.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-sdk-metrics.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-sdk-metrics) |
| [Trace SDK](./sdk/trace) | OpenTelemetry trace SDK | `opentelemetry-sdk-trace` | <!--VERSION_STABLE-->1.52.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-sdk-trace.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-sdk-trace) |
| [Log SDK](./sdk/logs) | OpenTelemetry log SDK | `opentelemetry-sdk-logs` | <!--VERSION_STABLE-->1.52.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-sdk-logs.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-sdk-logs) |
| [SDK Common](./sdk/common) | Shared SDK components | `opentelemetry-sdk-common` | <!--VERSION_STABLE-->1.52.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-sdk-common.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-sdk-common) |
| [SDK Testing](./sdk/testing) | Components for testing OpenTelemetry instrumentation | `opentelemetry-sdk-testing` | <!--VERSION_STABLE-->1.52.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-sdk-testing.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-sdk-testing) |
| [SDK](./sdk/all) | OpenTelemetry SDK, including metrics, traces, and logs | `opentelemetry-sdk` | <!--VERSION_STABLE-->1.46.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-sdk.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-sdk) |
| [Metrics SDK](./sdk/metrics) | OpenTelemetry metrics SDK | `opentelemetry-sdk-metrics` | <!--VERSION_STABLE-->1.46.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-sdk-metrics.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-sdk-metrics) |
| [Trace SDK](./sdk/trace) | OpenTelemetry trace SDK | `opentelemetry-sdk-trace` | <!--VERSION_STABLE-->1.46.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-sdk-trace.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-sdk-trace) |
| [Log SDK](./sdk/logs) | OpenTelemetry log SDK | `opentelemetry-sdk-logs` | <!--VERSION_STABLE-->1.46.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-sdk-logs.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-sdk-logs) |
| [SDK Common](./sdk/common) | Shared SDK components | `opentelemetry-sdk-common` | <!--VERSION_STABLE-->1.46.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-sdk-common.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-sdk-common) |
| [SDK Testing](./sdk/testing) | Components for testing OpenTelemetry instrumentation | `opentelemetry-sdk-testing` | <!--VERSION_STABLE-->1.46.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-sdk-testing.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-sdk-testing) |
</details>
<details>
@ -107,16 +103,16 @@ SDK exporters for shipping traces, metrics, and logs out of process.
| Component | Description | Artifact ID | Version | Javadoc |
|-----------------------------------------------------------------------|------------------------------------------------------------------------------|------------------------------------------------------|-------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [OTLP Exporters](./exporters/otlp/all) | OTLP gRPC & HTTP exporters, including traces, metrics, and logs | `opentelemetry-exporter-otlp` | <!--VERSION_STABLE-->1.52.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-exporter-otlp.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-exporter-otlp) |
| [OTLP Logging Exporters](./exporters/logging-otlp) | Logging exporters in OTLP JSON encoding, including traces, metrics, and logs | `opentelemetry-exporter-logging-otlp` | <!--VERSION_STABLE-->1.52.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-exporter-logging-otlp.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-exporter-logging-otlp) |
| [OTLP Common](./exporters/otlp/common) | Shared OTLP components (internal) | `opentelemetry-exporter-otlp-common` | <!--VERSION_STABLE-->1.52.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-exporter-otlp-common.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-exporter-otlp-common) |
| [Logging Exporter](./exporters/logging) | Logging exporters, including metrics, traces, and logs | `opentelemetry-exporter-logging` | <!--VERSION_STABLE-->1.52.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-exporter-logging.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-exporter-logging) |
| [Zipkin Exporter](./exporters/zipkin) | Zipkin trace exporter | `opentelemetry-exporter-zipkin` | <!--VERSION_STABLE-->1.52.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-exporter-zipkin.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-exporter-zipkin) |
| [Prometheus Exporter](./exporters/prometheus) | Prometheus metric exporter | `opentelemetry-exporter-prometheus` | <!--VERSION_UNSTABLE-->1.52.0-alpha<!--/VERSION_UNSTABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-exporter-prometheus.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-exporter-prometheus) |
| [Exporter Common](./exporters/common) | Shared exporter components (internal) | `opentelemetry-exporter-common` | <!--VERSION_STABLE-->1.52.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-exporter-common.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-exporter-common) |
| [OkHttp Sender](./exporters/sender/okhttp) | OkHttp implementation of HttpSender (internal) | `opentelemetry-exporter-sender-okhttp` | <!--VERSION_STABLE-->1.52.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-exporter-sender-okhttp.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-exporter-sender-okhttp) |
| [JDK Sender](./exporters/sender/jdk) | Java 11+ native HttpClient implementation of HttpSender (internal) | `opentelemetry-exporter-sender-jdk` | <!--VERSION_STABLE-->1.52.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-exporter-sender-jdk.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-exporter-sender-jdk) | |
| [gRPC ManagedChannel Sender](./exporters/sender/grpc-managed-channel) | gRPC ManagedChannel implementation of GrpcSender (internal) | `opentelemetry-exporter-sender-grpc-managed-channel` | <!--VERSION_STABLE-->1.52.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-exporter-sender-grpc-managed-channel.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-exporter-sender-grpc-managed-channel) | |
| [OTLP Exporters](./exporters/otlp/all) | OTLP gRPC & HTTP exporters, including traces, metrics, and logs | `opentelemetry-exporter-otlp` | <!--VERSION_STABLE-->1.46.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-exporter-otlp.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-exporter-otlp) |
| [OTLP Logging Exporters](./exporters/logging-otlp) | Logging exporters in OTLP JSON encoding, including traces, metrics, and logs | `opentelemetry-exporter-logging-otlp` | <!--VERSION_STABLE-->1.46.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-exporter-logging-otlp.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-exporter-logging-otlp) |
| [OTLP Common](./exporters/otlp/common) | Shared OTLP components (internal) | `opentelemetry-exporter-otlp-common` | <!--VERSION_STABLE-->1.46.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-exporter-otlp-common.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-exporter-otlp-common) |
| [Logging Exporter](./exporters/logging) | Logging exporters, including metrics, traces, and logs | `opentelemetry-exporter-logging` | <!--VERSION_STABLE-->1.46.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-exporter-logging.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-exporter-logging) |
| [Zipkin Exporter](./exporters/zipkin) | Zipkin trace exporter | `opentelemetry-exporter-zipkin` | <!--VERSION_STABLE-->1.46.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-exporter-zipkin.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-exporter-zipkin) |
| [Prometheus Exporter](./exporters/prometheus) | Prometheus metric exporter | `opentelemetry-exporter-prometheus` | <!--VERSION_UNSTABLE-->1.46.0-alpha<!--/VERSION_UNSTABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-exporter-prometheus.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-exporter-prometheus) |
| [Exporter Common](./exporters/common) | Shared exporter components (internal) | `opentelemetry-exporter-common` | <!--VERSION_STABLE-->1.46.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-exporter-common.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-exporter-common) |
| [OkHttp Sender](./exporters/sender/okhttp) | OkHttp implementation of HttpSender (internal) | `opentelemetry-exporter-sender-okhttp` | <!--VERSION_STABLE-->1.46.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-exporter-sender-okhttp.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-exporter-sender-okhttp) |
| [JDK Sender](./exporters/sender/jdk) | Java 11+ native HttpClient implementation of HttpSender (internal) | `opentelemetry-exporter-sender-jdk` | <!--VERSION_STABLE-->1.46.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-exporter-sender-jdk.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-exporter-sender-jdk) | |
| [gRPC ManagedChannel Sender](./exporters/sender/grpc-managed-channel) | gRPC ManagedChannel implementation of GrpcSender (internal) | `opentelemetry-exporter-sender-grpc-managed-channel` | <!--VERSION_STABLE-->1.46.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-exporter-sender-grpc-managed-channel.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-exporter-sender-grpc-managed-channel) | |
</details>
<details>
@ -126,10 +122,10 @@ Extensions to the OpenTelemetry SDK.
| Component | Description | Artifact ID | Version | Javadoc |
|-------------------------------------------------------------------------------|------------------------------------------------------------------------------------|-----------------------------------------------------|-------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [SDK Autoconfigure](./sdk-extensions/autoconfigure) | Autoconfigure OpenTelemetry SDK from env vars, system properties, and SPI | `opentelemetry-sdk-extension-autoconfigure` | <!--VERSION_STABLE-->1.52.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-sdk-extension-autoconfigure.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-sdk-extension-autoconfigure) |
| [SDK Autoconfigure SPI](./sdk-extensions/autoconfigure-spi) | Service Provider Interface (SPI) definitions for autoconfigure | `opentelemetry-sdk-extension-autoconfigure-spi` | <!--VERSION_STABLE-->1.52.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-sdk-extension-autoconfigure-spi.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-sdk-extension-autoconfigure-spi) |
| [SDK Jaeger Remote Sampler Extension](./sdk-extensions/jaeger-remote-sampler) | Sampler which obtains sampling configuration from remote Jaeger server | `opentelemetry-sdk-extension-jaeger-remote-sampler` | <!--VERSION_STABLE-->1.52.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-sdk-extension-jaeger-remote-sampler.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-sdk-extension-jaeger-remote-sampler) |
| [SDK Incubator](./sdk-extensions/incubator) | SDK incubator, including YAML based view configuration, LeakDetectingSpanProcessor | `opentelemetry-sdk-extension-incubator` | <!--VERSION_UNSTABLE-->1.52.0-alpha<!--/VERSION_UNSTABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-sdk-extension-incubator.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-sdk-extension-incubator) |
| [SDK Autoconfigure](./sdk-extensions/autoconfigure) | Autoconfigure OpenTelemetry SDK from env vars, system properties, and SPI | `opentelemetry-sdk-extension-autoconfigure` | <!--VERSION_STABLE-->1.46.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-sdk-extension-autoconfigure.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-sdk-extension-autoconfigure) |
| [SDK Autoconfigure SPI](./sdk-extensions/autoconfigure-spi) | Service Provider Interface (SPI) definitions for autoconfigure | `opentelemetry-sdk-extension-autoconfigure-spi` | <!--VERSION_STABLE-->1.46.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-sdk-extension-autoconfigure-spi.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-sdk-extension-autoconfigure-spi) |
| [SDK Jaeger Remote Sampler Extension](./sdk-extensions/jaeger-remote-sampler) | Sampler which obtains sampling configuration from remote Jaeger server | `opentelemetry-sdk-extension-jaeger-remote-sampler` | <!--VERSION_STABLE-->1.46.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-sdk-extension-jaeger-remote-sampler.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-sdk-extension-jaeger-remote-sampler) |
| [SDK Incubator](./sdk-extensions/incubator) | SDK incubator, including YAML based view configuration, LeakDetectingSpanProcessor | `opentelemetry-sdk-extension-incubator` | <!--VERSION_UNSTABLE-->1.46.0-alpha<!--/VERSION_UNSTABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-sdk-extension-incubator.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-sdk-extension-incubator) |
</details>
<details>
@ -139,8 +135,8 @@ Shims for bridging data from one observability library to another.
| Component | Description | Artifact ID | Version | Javadoc |
|----------------------------------------|--------------------------------------------------------------|----------------------------------|-------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [OpenCensus Shim](./opencensus-shim) | Bridge opencensus metrics into the OpenTelemetry metrics SDK | `opentelemetry-opencensus-shim` | <!--VERSION_UNSTABLE-->1.52.0-alpha<!--/VERSION_UNSTABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-opencensus-shim.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-opencensus-shim) |
| [OpenTracing Shim](./opentracing-shim) | Bridge opentracing spans into the OpenTelemetry trace API | `opentelemetry-opentracing-shim` | <!--VERSION_STABLE-->1.52.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-opentracing-shim.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-opentracing-shim) |
| [OpenCensus Shim](./opencensus-shim) | Bridge opencensus metrics into the OpenTelemetry metrics SDK | `opentelemetry-opencensus-shim` | <!--VERSION_UNSTABLE-->1.46.0-alpha<!--/VERSION_UNSTABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-opencensus-shim.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-opencensus-shim) |
| [OpenTracing Shim](./opentracing-shim) | Bridge opentracing spans into the OpenTelemetry trace API | `opentelemetry-opentracing-shim` | <!--VERSION_STABLE-->1.46.0<!--/VERSION_STABLE--> | [![Javadocs](https://www.javadoc.io/badge/io.opentelemetry/opentelemetry-opentracing-shim.svg)](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-opentracing-shim) |
</details>
## Dependencies
@ -177,11 +173,11 @@ Snapshots of the `main` branch are available as follows:
```groovy
repositories {
maven { url 'https://central.sonatype.com/repository/maven-snapshots/' }
maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }
}
dependencies {
implementation platform("io.opentelemetry:opentelemetry-bom:1.53.0-SNAPSHOT")
implementation platform("io.opentelemetry:opentelemetry-bom:1.47.0-SNAPSHOT")
implementation('io.opentelemetry:opentelemetry-api')
}
```
@ -194,8 +190,8 @@ dependencies {
<project>
<repositories>
<repository>
<id>sonatype-snapshot-repository</id>
<url>https://central.sonatype.com/repository/maven-snapshots/</url>
<id>oss.sonatype.org-snapshot</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</repository>
</repositories>
<dependencyManagement>
@ -203,7 +199,7 @@ dependencies {
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-bom</artifactId>
<version>1.53.0-SNAPSHOT</version>
<version>1.47.0-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
@ -255,35 +251,35 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for:
* Keys to successful PRs
* Guide to using gradle composite builds
### Maintainers
### Code owners
- [Jack Berg](https://github.com/jack-berg), New Relic
- [John Watson](https://github.com/jkwatson), Verta.ai
Triagers:
For more information about the maintainer role, see the [community repository](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#maintainer).
- [Gregor Zeitlinger](https://github.com/zeitlinger), Grafana Labs
### Approvers
*Find more about the triager role in [community repository](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#triager).*
Approvers ([@open-telemetry/java-approvers](https://github.com/orgs/open-telemetry/teams/java-approvers)):
- [Jason Plumb](https://github.com/breedx-splk), Splunk
- [Josh Suereth](https://github.com/jsuereth), Google
- [Lauri Tulmin](https://github.com/laurit), Splunk
- [Trask Stalnaker](https://github.com/trask), Microsoft
For more information about the approver role, see the [community repository](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#approver).
*Find more about the approver role in [community repository](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#approver).*
### Triagers
Maintainers ([@open-telemetry/java-maintainers](https://github.com/orgs/open-telemetry/teams/java-maintainers)):
- [Gregor Zeitlinger](https://github.com/zeitlinger), Grafana Labs
- [Jack Berg](https://github.com/jack-berg), New Relic
- [John Watson](https://github.com/jkwatson), Verta.ai
For more information about the triager role, see the [community repository](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#triager).
### Emeritus
Emeritus:
- Maintainer [Bogdan Drutu](https://github.com/BogdanDrutu)
- Maintainer [Carlos Alberto](https://github.com/carlosalberto)
- Approver [Mateusz Rzeszutek](https://github.com/mateuszrzeszutek)
For more information about the emeritus role, see the [community repository](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#emeritus-maintainerapprovertriager).
*Find more about the maintainer role in [community repository](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#maintainer).*
### Help wanted
@ -294,14 +290,18 @@ We are currently resource constrained and are actively seeking new contributors
- Issues labeled [help wanted](https://github.com/open-telemetry/opentelemetry-java/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22) are project priorities. Code contributions (or pull request reviews when a PR is linked) for these issues are particularly important.
- Triaging / responding to new issues and discussions is a great way to engage with the project.
### Thanks to all of our contributors!
### Thanks to all the people who have contributed
<a href="https://github.com/open-telemetry/opentelemetry-java/graphs/contributors">
<img alt="Repo contributors" src="https://contrib.rocks/image?repo=open-telemetry/opentelemetry-java" />
<img src="https://contrib.rocks/image?repo=open-telemetry/opentelemetry-java" />
</a>
Made with [contrib.rocks](https://contrib.rocks).
[ci-image]: https://github.com/open-telemetry/opentelemetry-java/workflows/Build/badge.svg
[ci-url]: https://github.com/open-telemetry/opentelemetry-java/actions?query=workflow%3ABuild+branch%3Amain
[codecov-image]: https://codecov.io/gh/open-telemetry/opentelemetry-java/branch/main/graph/badge.svg
[codecov-url]: https://app.codecov.io/gh/open-telemetry/opentelemetry-java/branch/main/
[dependencies-and-boms]: https://opentelemetry.io/docs/languages/java/intro/#dependencies-and-boms
[maven-image]: https://maven-badges.sml.io/maven-central/io.opentelemetry/opentelemetry-api/badge.svg
[maven-url]: https://maven-badges.sml.io/maven-central/io.opentelemetry/opentelemetry-api
[maven-image]: https://maven-badges.herokuapp.com/maven-central/io.opentelemetry/opentelemetry-api/badge.svg
[maven-url]: https://maven-badges.herokuapp.com/maven-central/io.opentelemetry/opentelemetry-api

View File

@ -57,17 +57,27 @@ and deadlocks.
* Review and merge the pull request that it creates for updating the change log in main
(note that if this is not a patch release then the change log on main may already be up-to-date,
in which case no pull request will be created).
* Once the release artifacts become available on Maven Central, the system will automatically
generate a new pull request titled `Update apidiff baseline and documentation versions to
released version $VERSION`. This pull request will contain updates to both the API diff baseline
and version references in the documentation files (README.md). Please review and merge this
automated pull request.
* The [website](https://github.com/open-telemetry/opentelemetry.io) contains automation to update
to the newly released version. Review and approve the pull request when available.
* The [website](https://opentelemetry.io/docs/languages/java/configuration/#zero-code-sdk-autoconfigure)
contains documentation on autoconfiguration properties. If the release has updated or modified any
properties, open and merge a pull request to update the documentation.
## Update release versions in documentations
After releasing is done, you need to first update the docs. This needs to happen after artifacts have propagated
to Maven Central so should probably be done an hour or two after the release workflow finishes.
```
./gradlew updateVersionInDocs -Prelease.version=x.y.z
./gradlew japicmp -PapiBaseVersion=a.b.c -PapiNewVersion=x.y.z
./gradlew --refresh-dependencies japicmp
```
Where `x.y.z` is the version just released and `a.b.c` is the previous version.
Create a PR against the main branch with the changes.
## Credentials
The following credentials are required for building or publishing (and automatically set in Github Actions):

View File

@ -72,8 +72,8 @@ respect to semantic versioning.
| Language | Minimum Version | Applicability | Semconv Notes |
|----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Java | 8+ | All artifacts, unless otherwise noted | Changing requires major version bump. |
| Android | 23+ (NOTE: [desugaring](https://developer.android.com/studio/write/java8-support#library-desugaring) is required. We stay up to date with the latest version of [desugar_jdk_libs](https://github.com/google/desugar_jdk_libs).) | Artifacts using `otel.animalsniffer-conventions` plugin | Kept in sync with minimum requirements for [Google Play services](https://developers.google.com/android/guides/setup). Subject to change in minor version. |
| Kotlin | 1.8+ | Only applies to `opentelemetry-extension-kotlin` | Kept in sync with [minimum non-deprecated](https://kotlinlang.org/docs/gradle-compiler-options.html#attributes-common-to-jvm-and-js) version. Subject to change in minor versions. |
| Android | 21+ (NOTE: [desugaring](https://developer.android.com/studio/write/java8-support#library-desugaring) is required. We stay up to date with the latest version of [desugar_jdk_libs](https://github.com/google/desugar_jdk_libs).) | Artifacts using `otel.animalsniffer-conventions` plugin | Kept in sync with minimum requirements for [Google Play services](https://developers.google.com/android/guides/setup). Subject to change in minor version. |
| Kotlin | 1.6+ | Only applies to `opentelemetry-extension-kotlin` | Kept in sync with [minimum non-deprecated](https://kotlinlang.org/docs/gradle-compiler-options.html#attributes-common-to-jvm-and-js) version. Subject to change in minor versions. |
## API vs SDK

View File

@ -28,7 +28,7 @@ class SdkDesignTest {
* Ensures that all SDK methods that: - are defined in classes that extend or implement API model
* and are public (to exclude protected builders) - are public (avoids issues with protected
* methods returning classes unavailable to test's CL) - override or implement parent method
* return only API, Context, Common, or generic Java type.
* return only API, Context or generic Java type.
*/
@Test
void sdkImplementationOfApiClassesShouldReturnApiTypeOnly() {
@ -45,11 +45,7 @@ class SdkDesignTest {
.and(implementOrOverride())
.should()
.haveRawReturnType(
inPackage(
"io.opentelemetry.api..",
"io.opentelemetry.context..",
"io.opentelemetry.common..",
"java.."))
inPackage("io.opentelemetry.api..", "io.opentelemetry.context..", "java.."))
.orShould()
.haveRawReturnType("void");

View File

@ -27,7 +27,7 @@ configurations.add(signatureJarClasspath)
configurations.add(generatedSignature)
dependencies {
signature("com.toasttab.android:gummy-bears-api-23:0.12.0@signature")
signature("com.toasttab.android:gummy-bears-api-21:0.10.0@signature")
signatureJar("com.android.tools:desugar_jdk_libs")
}

View File

@ -17,7 +17,6 @@ import io.opentelemetry.api.trace.TracerProvider;
import io.opentelemetry.context.propagation.ContextPropagators;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.function.Supplier;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Nullable;
@ -117,21 +116,6 @@ public final class GlobalOpenTelemetry {
}
}
/**
* Sets the {@link OpenTelemetry} that should be the global instance.
*
* <p>This method calls the given {@code supplier} and calls {@link #set(OpenTelemetry)}, all
* while holding the {@link GlobalOpenTelemetry} mutex.
*
* @since 1.52.0
*/
public static void set(Supplier<OpenTelemetry> supplier) {
synchronized (mutex) {
OpenTelemetry openTelemetry = supplier.get();
set(openTelemetry);
}
}
/** Returns the globally registered {@link TracerProvider}. */
public static TracerProvider getTracerProvider() {
return get().getTracerProvider();

View File

@ -16,6 +16,7 @@ import io.opentelemetry.context.Context;
import io.opentelemetry.context.propagation.TextMapGetter;
import io.opentelemetry.context.propagation.TextMapPropagator;
import io.opentelemetry.context.propagation.TextMapSetter;
import io.opentelemetry.context.propagation.internal.ExtendedTextMapGetter;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
@ -96,11 +97,33 @@ public final class W3CBaggagePropagator implements TextMapPropagator {
return context;
}
return extractMulti(context, carrier, getter);
if (getter instanceof ExtendedTextMapGetter) {
return extractMulti(context, carrier, (ExtendedTextMapGetter<C>) getter);
}
return extractSingle(context, carrier, getter);
}
private static <C> Context extractSingle(
Context context, @Nullable C carrier, TextMapGetter<C> getter) {
String baggageHeader = getter.get(carrier, FIELD);
if (baggageHeader == null) {
return context;
}
if (baggageHeader.isEmpty()) {
return context;
}
BaggageBuilder baggageBuilder = Baggage.builder();
try {
extractEntries(baggageHeader, baggageBuilder);
} catch (RuntimeException e) {
return context;
}
return context.with(baggageBuilder.build());
}
private static <C> Context extractMulti(
Context context, @Nullable C carrier, TextMapGetter<C> getter) {
Context context, @Nullable C carrier, ExtendedTextMapGetter<C> getter) {
Iterator<String> baggageHeaders = getter.getAll(carrier, FIELD);
if (baggageHeaders == null) {
return context;

View File

@ -9,7 +9,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import javax.annotation.Nullable;
class ArrayBackedAttributesBuilder implements AttributesBuilder {
private final List<Object> data;
@ -38,7 +37,7 @@ class ArrayBackedAttributesBuilder implements AttributesBuilder {
}
@Override
public <T> AttributesBuilder put(AttributeKey<T> key, @Nullable T value) {
public <T> AttributesBuilder put(AttributeKey<T> key, T value) {
if (key == null || key.getKey().isEmpty() || value == null) {
return this;
}

View File

@ -26,11 +26,6 @@ public interface AttributeKey<T> {
/** Returns the type of attribute for this key. Useful for building switch statements. */
AttributeType getType();
// TODO (jack-berg): uncomment when extended attributes are promoted from incubator to API
// default ExtendedAttributeKey<T> asExtendedAttributeKey() {
// return InternalAttributeKeyImpl.toExtendedAttributeKey(this);
// }
/** Returns a new AttributeKey for String valued attributes. */
static AttributeKey<String> stringKey(String key) {
return InternalAttributeKeyImpl.create(key, AttributeType.STRING);

View File

@ -18,7 +18,6 @@ import static io.opentelemetry.api.common.AttributeKey.stringKey;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import javax.annotation.Nullable;
/** A builder of {@link Attributes} supporting an arbitrary number of key-value pairs. */
public interface AttributesBuilder {
@ -36,22 +35,18 @@ public interface AttributesBuilder {
// version.
<T> AttributesBuilder put(AttributeKey<Long> key, int value);
/**
* Puts an {@link AttributeKey} with an associated value into this if the value is non-null.
* Providing a null value does not remove or unset previously set values.
*/
<T> AttributesBuilder put(AttributeKey<T> key, @Nullable T value);
/** Puts a {@link AttributeKey} with associated value into this. */
<T> AttributesBuilder put(AttributeKey<T> key, T value);
/**
* Puts a String attribute into this if the value is non-null. Providing a null value does not
* remove or unset previously set values.
* Puts a String attribute into this.
*
* <p>Note: It is strongly recommended to use {@link #put(AttributeKey, Object)}, and pre-allocate
* your keys, if possible.
*
* @return this Builder
*/
default AttributesBuilder put(String key, @Nullable String value) {
default AttributesBuilder put(String key, String value) {
return put(stringKey(key), value);
}

View File

@ -10,7 +10,6 @@ import io.opentelemetry.api.common.Value;
import io.opentelemetry.context.Context;
import java.time.Instant;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nullable;
class DefaultLogger implements Logger {
@ -78,7 +77,7 @@ class DefaultLogger implements Logger {
}
@Override
public <T> LogRecordBuilder setAttribute(AttributeKey<T> key, @Nullable T value) {
public <T> LogRecordBuilder setAttribute(AttributeKey<T> key, T value) {
return this;
}

View File

@ -5,18 +5,12 @@
package io.opentelemetry.api.logs;
import static io.opentelemetry.api.common.AttributeKey.booleanKey;
import static io.opentelemetry.api.common.AttributeKey.doubleKey;
import static io.opentelemetry.api.common.AttributeKey.longKey;
import static io.opentelemetry.api.common.AttributeKey.stringKey;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.common.Value;
import io.opentelemetry.context.Context;
import java.time.Instant;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nullable;
/**
* Used to construct and emit log records from a {@link Logger}.
@ -104,111 +98,8 @@ public interface LogRecordBuilder {
return this;
}
/**
* Sets an attribute on the {@code LogRecord}. If the {@code LogRecord} previously contained a
* mapping for the key, the old value is replaced by the specified value.
*
* <p>Note: Providing a null value is a no-op and will not remove previously set values.
*
* @param key the key for this attribute.
* @param value the value for this attribute.
* @return this.
*/
<T> LogRecordBuilder setAttribute(AttributeKey<T> key, @Nullable T value);
/**
* Sets a String attribute on the {@code LogRecord}. If the {@code LogRecord} previously contained
* a mapping for the key, the old value is replaced by the specified value.
*
* <p>Note: Providing a null value is a no-op and will not remove previously set values.
*
* <p>Note: It is strongly recommended to use {@link #setAttribute(AttributeKey, Object)}, and
* pre-allocate your keys, if possible.
*
* @param key the key for this attribute.
* @param value the value for this attribute.
* @return this.
* @since 1.48.0
*/
default LogRecordBuilder setAttribute(String key, @Nullable String value) {
return setAttribute(stringKey(key), value);
}
/**
* Sets a Long attribute on the {@code LogRecord}. If the {@code LogRecord} previously contained a
* mapping for the key, the old value is replaced by the specified value.
*
* <p>Note: It is strongly recommended to use {@link #setAttribute(AttributeKey, Object)}, and
* pre-allocate your keys, if possible.
*
* @param key the key for this attribute.
* @param value the value for this attribute.
* @return this.
* @since 1.48.0
*/
default LogRecordBuilder setAttribute(String key, long value) {
return setAttribute(longKey(key), value);
}
/**
* Sets a Double attribute on the {@code LogRecord}. If the {@code LogRecord} previously contained
* a mapping for the key, the old value is replaced by the specified value.
*
* <p>Note: It is strongly recommended to use {@link #setAttribute(AttributeKey, Object)}, and
* pre-allocate your keys, if possible.
*
* @param key the key for this attribute.
* @param value the value for this attribute.
* @return this.
* @since 1.48.0
*/
default LogRecordBuilder setAttribute(String key, double value) {
return setAttribute(doubleKey(key), value);
}
/**
* Sets a Boolean attribute on the {@code LogRecord}. If the {@code LogRecord} previously
* contained a mapping for the key, the old value is replaced by the specified value.
*
* <p>Note: It is strongly recommended to use {@link #setAttribute(AttributeKey, Object)}, and
* pre-allocate your keys, if possible.
*
* @param key the key for this attribute.
* @param value the value for this attribute.
* @return this.
* @since 1.48.0
*/
default LogRecordBuilder setAttribute(String key, boolean value) {
return setAttribute(booleanKey(key), value);
}
/**
* Sets an Integer attribute on the {@code LogRecord}. If the {@code LogRecord} previously
* contained a mapping for the key, the old value is replaced by the specified value.
*
* <p>Note: It is strongly recommended to use {@link #setAttribute(AttributeKey, Object)}, and
* pre-allocate your keys, if possible.
*
* @param key the key for this attribute.
* @param value the value for this attribute.
* @return this.
* @since 1.48.0
*/
default LogRecordBuilder setAttribute(String key, int value) {
return setAttribute(key, (long) value);
}
/**
* Sets the event name, which identifies the class / type of the Event.
*
* <p>This name should uniquely identify the event structure (both attributes and body). A log
* record with a non-empty event name is an Event.
*
* @since 1.50.0
*/
default LogRecordBuilder setEventName(String eventName) {
return this;
}
/** Sets an attribute. */
<T> LogRecordBuilder setAttribute(AttributeKey<T> key, T value);
/** Emit the log record. */
void emit();

View File

@ -8,7 +8,6 @@ package io.opentelemetry.api.trace;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
/**
@ -43,7 +42,7 @@ final class PropagatedSpan implements Span {
}
@Override
public Span setAttribute(String key, @Nullable String value) {
public Span setAttribute(String key, String value) {
return this;
}
@ -63,7 +62,7 @@ final class PropagatedSpan implements Span {
}
@Override
public <T> Span setAttribute(AttributeKey<T> key, @Nullable T value) {
public <T> Span setAttribute(AttributeKey<T> key, T value) {
return this;
}

View File

@ -88,9 +88,7 @@ public interface Span extends ImplicitContextKeyed {
* Sets an attribute to the {@code Span}. If the {@code Span} previously contained a mapping for
* the key, the old value is replaced by the specified value.
*
* <p>Empty String "" and null are valid attribute {@code value}s, but not valid keys.
*
* <p>Note: Providing a null value is a no-op and will not remove previously set values.
* <p>Empty String "" and null are valid attribute {@code value}, but not valid keys.
*
* <p>Note: It is strongly recommended to use {@link #setAttribute(AttributeKey, Object)}, and
* pre-allocate your keys, if possible.
@ -99,7 +97,7 @@ public interface Span extends ImplicitContextKeyed {
* @param value the value for this attribute.
* @return this.
*/
default Span setAttribute(String key, @Nullable String value) {
default Span setAttribute(String key, String value) {
return setAttribute(AttributeKey.stringKey(key), value);
}
@ -152,13 +150,13 @@ public interface Span extends ImplicitContextKeyed {
* Sets an attribute to the {@code Span}. If the {@code Span} previously contained a mapping for
* the key, the old value is replaced by the specified value.
*
* <p>Note: Providing a null value is a no-op.
* <p>Note: the behavior of null values is undefined, and hence strongly discouraged.
*
* @param key the key for this attribute.
* @param value the value for this attribute.
* @return this.
*/
<T> Span setAttribute(AttributeKey<T> key, @Nullable T value);
<T> Span setAttribute(AttributeKey<T> key, T value);
/**
* Sets an attribute to the {@code Span}. If the {@code Span} previously contained a mapping for

View File

@ -14,6 +14,7 @@ import io.opentelemetry.api.baggage.Baggage;
import io.opentelemetry.api.baggage.BaggageEntryMetadata;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.propagation.TextMapGetter;
import io.opentelemetry.context.propagation.internal.ExtendedTextMapGetter;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
@ -39,8 +40,8 @@ class W3CBaggagePropagatorTest {
}
};
private static final TextMapGetter<Map<String, List<String>>> multiGetter =
new TextMapGetter<Map<String, List<String>>>() {
private static final ExtendedTextMapGetter<Map<String, List<String>>> multiGetter =
new ExtendedTextMapGetter<Map<String, List<String>>>() {
@Override
public Iterable<String> keys(Map<String, List<String>> carrier) {
return carrier.keySet();

View File

@ -26,7 +26,6 @@ import java.util.LinkedHashMap;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.annotation.Nullable;
import org.junit.jupiter.api.Test;
/** Unit tests for {@link Attributes}s. */
@ -566,7 +565,7 @@ class AttributesTest {
}
@Override
public <T> AttributesBuilder put(AttributeKey<T> key, @Nullable T value) {
public <T> AttributesBuilder put(AttributeKey<T> key, T value) {
return null;
}

View File

@ -7,7 +7,6 @@ Experimental APIs, including Event API, extended Log Bridge APIs, extended Metri
Features:
* Check if logger is enabled before emitting logs to avoid unnecessary computation
* Add extended attributes to log records to encode complex data structures
See [ExtendedLogsBridgeApiUsageTest](./src/test/java/io/opentelemetry/api/incubator/logs/ExtendedLogsBridgeApiUsageTest.java).

View File

@ -12,14 +12,8 @@ otelJava.moduleName.set("io.opentelemetry.api.incubator")
dependencies {
api(project(":api:all"))
// Supports optional InstrumentationConfigUtil#convertToModel
compileOnly("com.fasterxml.jackson.core:jackson-databind")
annotationProcessor("com.google.auto.value:auto-value")
// To use parsed config file as input for InstrumentationConfigUtilTest
testImplementation(project(":sdk-extensions:incubator"))
testImplementation(project(":sdk:testing"))
testImplementation(project(":api:testing-internal"))
@ -27,16 +21,3 @@ dependencies {
testImplementation("com.google.guava:guava")
}
testing {
suites {
register<JvmTestSuite>("testConvertToModel") {
dependencies {
implementation("com.fasterxml.jackson.core:jackson-databind")
implementation(project(":sdk-extensions:incubator"))
implementation(project(":sdk-extensions:autoconfigure"))
implementation("com.google.guava:guava")
}
}
}
}

View File

@ -1,86 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.incubator.common;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.common.AttributesBuilder;
import io.opentelemetry.api.internal.ImmutableKeyValuePairs;
import java.util.ArrayList;
import java.util.Comparator;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
@Immutable
final class ArrayBackedExtendedAttributes
extends ImmutableKeyValuePairs<ExtendedAttributeKey<?>, Object> implements ExtendedAttributes {
// We only compare the key name, not type, when constructing, to allow deduping keys with the
// same name but different type.
private static final Comparator<ExtendedAttributeKey<?>> KEY_COMPARATOR_FOR_CONSTRUCTION =
Comparator.comparing(ExtendedAttributeKey::getKey);
static final ExtendedAttributes EMPTY = ExtendedAttributes.builder().build();
@Nullable private Attributes attributes;
private ArrayBackedExtendedAttributes(
Object[] data, Comparator<ExtendedAttributeKey<?>> keyComparator) {
super(data, keyComparator);
}
/**
* Only use this constructor if you can guarantee that the data has been de-duped, sorted by key
* and contains no null values or null/empty keys.
*
* @param data the raw data
*/
ArrayBackedExtendedAttributes(Object[] data) {
super(data);
}
@Override
public ExtendedAttributesBuilder toBuilder() {
return new ArrayBackedExtendedAttributesBuilder(new ArrayList<>(data()));
}
@SuppressWarnings("unchecked")
@Override
@Nullable
public <T> T get(ExtendedAttributeKey<T> key) {
return (T) super.get(key);
}
@SuppressWarnings("unchecked")
@Override
public Attributes asAttributes() {
if (attributes == null) {
AttributesBuilder builder = Attributes.builder();
forEach(
(extendedAttributeKey, value) -> {
AttributeKey<Object> attributeKey =
(AttributeKey<Object>) extendedAttributeKey.asAttributeKey();
if (attributeKey != null) {
builder.put(attributeKey, value);
}
});
attributes = builder.build();
}
return attributes;
}
static ExtendedAttributes sortAndFilterToAttributes(Object... data) {
// null out any empty keys or keys with null values
// so they will then be removed by the sortAndFilter method.
for (int i = 0; i < data.length; i += 2) {
ExtendedAttributeKey<?> key = (ExtendedAttributeKey<?>) data[i];
if (key != null && key.getKey().isEmpty()) {
data[i] = null;
}
}
return new ArrayBackedExtendedAttributes(data, KEY_COMPARATOR_FOR_CONSTRUCTION);
}
}

View File

@ -1,84 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.incubator.common;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
class ArrayBackedExtendedAttributesBuilder implements ExtendedAttributesBuilder {
private final List<Object> data;
ArrayBackedExtendedAttributesBuilder() {
data = new ArrayList<>();
}
ArrayBackedExtendedAttributesBuilder(List<Object> data) {
this.data = data;
}
@Override
public ExtendedAttributes build() {
// If only one key-value pair AND the entry hasn't been set to null (by #remove(AttributeKey<T>)
// or #removeIf(Predicate<AttributeKey<?>>)), then we can bypass sorting and filtering
if (data.size() == 2 && data.get(0) != null) {
return new ArrayBackedExtendedAttributes(data.toArray());
}
return ArrayBackedExtendedAttributes.sortAndFilterToAttributes(data.toArray());
}
@Override
public <T> ExtendedAttributesBuilder put(ExtendedAttributeKey<T> key, T value) {
if (key == null || key.getKey().isEmpty() || value == null) {
return this;
}
data.add(key);
data.add(value);
return this;
}
@Override
public ExtendedAttributesBuilder removeIf(Predicate<ExtendedAttributeKey<?>> predicate) {
if (predicate == null) {
return this;
}
for (int i = 0; i < data.size() - 1; i += 2) {
Object entry = data.get(i);
if (entry instanceof ExtendedAttributeKey
&& predicate.test((ExtendedAttributeKey<?>) entry)) {
// null items are filtered out in ArrayBackedAttributes
data.set(i, null);
data.set(i + 1, null);
}
}
return this;
}
static List<Double> toList(double... values) {
Double[] boxed = new Double[values.length];
for (int i = 0; i < values.length; i++) {
boxed[i] = values[i];
}
return Arrays.asList(boxed);
}
static List<Long> toList(long... values) {
Long[] boxed = new Long[values.length];
for (int i = 0; i < values.length; i++) {
boxed[i] = values[i];
}
return Arrays.asList(boxed);
}
static List<Boolean> toList(boolean... values) {
Boolean[] boxed = new Boolean[values.length];
for (int i = 0; i < values.length; i++) {
boxed[i] = values[i];
}
return Arrays.asList(boxed);
}
}

View File

@ -1,100 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.incubator.common;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.incubator.internal.InternalExtendedAttributeKeyImpl;
import java.util.List;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
/**
* This interface provides a handle for setting the values of {@link ExtendedAttributes}. The type
* of value that can be set with an implementation of this key is denoted by the type parameter.
*
* <p>Implementations MUST be immutable, as these are used as the keys to Maps.
*
* <p>The allowed {@link #getType()}s is a superset of those allowed in {@link AttributeKey}.
*
* <p>Convenience methods are provided for translating to / from {@link AttributeKey}:
*
* <ul>
* <li>{@link #asAttributeKey()} converts from {@link ExtendedAttributeKey} to {@link
* AttributeKey}
* <li>{@link #fromAttributeKey(AttributeKey)} converts from {@link AttributeKey} to {@link
* ExtendedAttributeKey}
* </ul>
*
* @param <T> The type of value that can be set with the key.
*/
@Immutable
public interface ExtendedAttributeKey<T> {
/** Returns the underlying String representation of the key. */
String getKey();
/** Returns the type of attribute for this key. Useful for building switch statements. */
ExtendedAttributeType getType();
/**
* Return the equivalent {@link AttributeKey}, or {@code null} if the {@link #getType()} has no
* equivalent {@link io.opentelemetry.api.common.AttributeType}.
*/
@Nullable
default AttributeKey<T> asAttributeKey() {
return InternalExtendedAttributeKeyImpl.toAttributeKey(this);
}
/** Return an ExtendedAttributeKey equivalent to the {@code attributeKey}. */
// TODO (jack-berg): remove once AttributeKey.asExtendedAttributeKey is available
static <T> ExtendedAttributeKey<T> fromAttributeKey(AttributeKey<T> attributeKey) {
return InternalExtendedAttributeKeyImpl.toExtendedAttributeKey(attributeKey);
}
/** Returns a new ExtendedAttributeKey for String valued attributes. */
static ExtendedAttributeKey<String> stringKey(String key) {
return fromAttributeKey(AttributeKey.stringKey(key));
}
/** Returns a new ExtendedAttributeKey for Boolean valued attributes. */
static ExtendedAttributeKey<Boolean> booleanKey(String key) {
return fromAttributeKey(AttributeKey.booleanKey(key));
}
/** Returns a new ExtendedAttributeKey for Long valued attributes. */
static ExtendedAttributeKey<Long> longKey(String key) {
return fromAttributeKey(AttributeKey.longKey(key));
}
/** Returns a new ExtendedAttributeKey for Double valued attributes. */
static ExtendedAttributeKey<Double> doubleKey(String key) {
return fromAttributeKey(AttributeKey.doubleKey(key));
}
/** Returns a new ExtendedAttributeKey for List&lt;String&gt; valued attributes. */
static ExtendedAttributeKey<List<String>> stringArrayKey(String key) {
return fromAttributeKey(AttributeKey.stringArrayKey(key));
}
/** Returns a new ExtendedAttributeKey for List&lt;Boolean&gt; valued attributes. */
static ExtendedAttributeKey<List<Boolean>> booleanArrayKey(String key) {
return fromAttributeKey(AttributeKey.booleanArrayKey(key));
}
/** Returns a new ExtendedAttributeKey for List&lt;Long&gt; valued attributes. */
static ExtendedAttributeKey<List<Long>> longArrayKey(String key) {
return fromAttributeKey(AttributeKey.longArrayKey(key));
}
/** Returns a new ExtendedAttributeKey for List&lt;Double&gt; valued attributes. */
static ExtendedAttributeKey<List<Double>> doubleArrayKey(String key) {
return fromAttributeKey(AttributeKey.doubleArrayKey(key));
}
/** Returns a new ExtendedAttributeKey for Map valued attributes. */
static ExtendedAttributeKey<ExtendedAttributes> extendedAttributesKey(String key) {
return InternalExtendedAttributeKeyImpl.create(key, ExtendedAttributeType.EXTENDED_ATTRIBUTES);
}
}

View File

@ -1,26 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.incubator.common;
/**
* An enum that represents all the possible value types for an {@link ExtendedAttributeKey} and
* hence the types of values that are allowed for {@link ExtendedAttributes}.
*
* <p>This is a superset of {@link io.opentelemetry.api.common.AttributeType},
*/
public enum ExtendedAttributeType {
// Types copied AttributeType
STRING,
BOOLEAN,
LONG,
DOUBLE,
STRING_ARRAY,
BOOLEAN_ARRAY,
LONG_ARRAY,
DOUBLE_ARRAY,
// Extended types unique to ExtendedAttributes
EXTENDED_ATTRIBUTES;
}

View File

@ -1,103 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.incubator.common;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.incubator.logs.ExtendedLogRecordBuilder;
import java.util.Map;
import java.util.function.BiConsumer;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
/**
* An immutable container for extended attributes.
*
* <p>"extended" refers an extended set of allowed value types compared to standard {@link
* Attributes}. Notably, {@link ExtendedAttributes} values can be of type {@link
* ExtendedAttributeType#EXTENDED_ATTRIBUTES}, allowing nested {@link ExtendedAttributes} of
* arbitrary depth.
*
* <p>Where standard {@link Attributes} are accepted everyone that OpenTelemetry represents key /
* value pairs, {@link ExtendedAttributes} are only accepted in select places, such as log records
* (e.g. {@link ExtendedLogRecordBuilder#setAttribute(ExtendedAttributeKey, Object)}).
*
* <p>The keys are {@link ExtendedAttributeKey}s and the values are Object instances that match the
* type of the provided key.
*
* <p>Null keys will be silently dropped.
*
* <p>Note: The behavior of null-valued attributes is undefined, and hence strongly discouraged.
*
* <p>Implementations of this interface *must* be immutable and have well-defined value-based
* equals/hashCode implementations. If an implementation does not strictly conform to these
* requirements, behavior of the OpenTelemetry APIs and default SDK cannot be guaranteed.
*
* <p>For this reason, it is strongly suggested that you use the implementation that is provided
* here via the factory methods and the {@link ExtendedAttributesBuilder}.
*
* <p>Convenience methods are provided for translating to / from {@link Attributes}:
*
* <ul>
* <li>{@link #asAttributes()} converts from {@link ExtendedAttributes} to {@link Attributes}
* <li>{@link ExtendedAttributesBuilder#putAll(Attributes)} converts from {@link Attributes} to
* {@link ExtendedAttributes}
* <li>{@link #get(AttributeKey)} supports reading values using standard {@link AttributeKey}
* </ul>
*/
@Immutable
public interface ExtendedAttributes {
/** Returns the value for the given {@link AttributeKey}, or {@code null} if not found. */
@Nullable
default <T> T get(AttributeKey<T> key) {
if (key == null) {
return null;
}
return get(ExtendedAttributeKey.fromAttributeKey(key));
}
/** Returns the value for the given {@link ExtendedAttributeKey}, or {@code null} if not found. */
@Nullable
<T> T get(ExtendedAttributeKey<T> key);
/** Iterates over all the key-value pairs of attributes contained by this instance. */
void forEach(BiConsumer<? super ExtendedAttributeKey<?>, ? super Object> consumer);
/** The number of attributes contained in this. */
int size();
/** Whether there are any attributes contained in this. */
boolean isEmpty();
/** Returns a read-only view of this {@link ExtendedAttributes} as a {@link Map}. */
Map<ExtendedAttributeKey<?>, Object> asMap();
/**
* Return a view of this extended attributes with entries limited to those representable as
* standard attributes.
*/
Attributes asAttributes();
/** Returns a {@link ExtendedAttributes} instance with no attributes. */
static ExtendedAttributes empty() {
return ArrayBackedExtendedAttributes.EMPTY;
}
/**
* Returns a new {@link ExtendedAttributesBuilder} instance for creating arbitrary {@link
* ExtendedAttributes}.
*/
static ExtendedAttributesBuilder builder() {
return new ArrayBackedExtendedAttributesBuilder();
}
/**
* Returns a new {@link ExtendedAttributesBuilder} instance populated with the data of this {@link
* ExtendedAttributes}.
*/
ExtendedAttributesBuilder toBuilder();
}

View File

@ -1,233 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.incubator.common;
import static io.opentelemetry.api.incubator.common.ArrayBackedExtendedAttributesBuilder.toList;
import static io.opentelemetry.api.incubator.common.ExtendedAttributeKey.booleanArrayKey;
import static io.opentelemetry.api.incubator.common.ExtendedAttributeKey.booleanKey;
import static io.opentelemetry.api.incubator.common.ExtendedAttributeKey.doubleArrayKey;
import static io.opentelemetry.api.incubator.common.ExtendedAttributeKey.doubleKey;
import static io.opentelemetry.api.incubator.common.ExtendedAttributeKey.longArrayKey;
import static io.opentelemetry.api.incubator.common.ExtendedAttributeKey.longKey;
import static io.opentelemetry.api.incubator.common.ExtendedAttributeKey.stringArrayKey;
import static io.opentelemetry.api.incubator.common.ExtendedAttributeKey.stringKey;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
/** A builder of {@link ExtendedAttributes} supporting an arbitrary number of key-value pairs. */
public interface ExtendedAttributesBuilder {
/** Create the {@link ExtendedAttributes} from this. */
ExtendedAttributes build();
/** Puts a {@link AttributeKey} with associated value into this. */
default <T> ExtendedAttributesBuilder put(AttributeKey<T> key, T value) {
if (key == null || key.getKey().isEmpty() || value == null) {
return this;
}
return put(ExtendedAttributeKey.fromAttributeKey(key), value);
}
/** Puts a {@link ExtendedAttributeKey} with associated value into this. */
<T> ExtendedAttributesBuilder put(ExtendedAttributeKey<T> key, T value);
/**
* Puts a String attribute into this.
*
* <p>Note: It is strongly recommended to use {@link #put(ExtendedAttributeKey, Object)}, and
* pre-allocate your keys, if possible.
*
* @return this Builder
*/
default ExtendedAttributesBuilder put(String key, String value) {
return put(stringKey(key), value);
}
/**
* Puts a long attribute into this.
*
* <p>Note: It is strongly recommended to use {@link #put(ExtendedAttributeKey, Object)}, and
* pre-allocate your keys, if possible.
*
* @return this Builder
*/
default ExtendedAttributesBuilder put(String key, long value) {
return put(longKey(key), value);
}
/**
* Puts a double attribute into this.
*
* <p>Note: It is strongly recommended to use {@link #put(ExtendedAttributeKey, Object)}, and
* pre-allocate your keys, if possible.
*
* @return this Builder
*/
default ExtendedAttributesBuilder put(String key, double value) {
return put(doubleKey(key), value);
}
/**
* Puts a boolean attribute into this.
*
* <p>Note: It is strongly recommended to use {@link #put(ExtendedAttributeKey, Object)}, and
* pre-allocate your keys, if possible.
*
* @return this Builder
*/
default ExtendedAttributesBuilder put(String key, boolean value) {
return put(booleanKey(key), value);
}
/**
* Puts a {@link ExtendedAttributes} attribute into this.
*
* <p>Note: It is strongly recommended to use {@link #put(ExtendedAttributeKey, Object)}, and
* pre-allocate your keys, if possible.
*
* @return this Builder
*/
default <T> ExtendedAttributesBuilder put(String key, ExtendedAttributes value) {
return put(ExtendedAttributeKey.extendedAttributesKey(key), value);
}
/**
* Puts a String array attribute into this.
*
* <p>Note: It is strongly recommended to use {@link #put(ExtendedAttributeKey, Object)}, and
* pre-allocate your keys, if possible.
*
* @return this Builder
*/
default ExtendedAttributesBuilder put(String key, String... value) {
if (value == null) {
return this;
}
return put(stringArrayKey(key), Arrays.asList(value));
}
/**
* Puts a List attribute into this.
*
* @return this Builder
*/
@SuppressWarnings("unchecked")
default <T> ExtendedAttributesBuilder put(AttributeKey<List<T>> key, T... value) {
if (value == null) {
return this;
}
return put(key, Arrays.asList(value));
}
/**
* Puts a Long array attribute into this.
*
* <p>Note: It is strongly recommended to use {@link #put(ExtendedAttributeKey, Object)}, and
* pre-allocate your keys, if possible.
*
* @return this Builder
*/
default ExtendedAttributesBuilder put(String key, long... value) {
if (value == null) {
return this;
}
return put(longArrayKey(key), toList(value));
}
/**
* Puts a Double array attribute into this.
*
* <p>Note: It is strongly recommended to use {@link #put(ExtendedAttributeKey, Object)}, and
* pre-allocate your keys, if possible.
*
* @return this Builder
*/
default ExtendedAttributesBuilder put(String key, double... value) {
if (value == null) {
return this;
}
return put(doubleArrayKey(key), toList(value));
}
/**
* Puts a Boolean array attribute into this.
*
* <p>Note: It is strongly recommended to use {@link #put(ExtendedAttributeKey, Object)}, and
* pre-allocate your keys, if possible.
*
* @return this Builder
*/
default ExtendedAttributesBuilder put(String key, boolean... value) {
if (value == null) {
return this;
}
return put(booleanArrayKey(key), toList(value));
}
/**
* Puts all the provided attributes into this Builder.
*
* @return this Builder
*/
@SuppressWarnings({"unchecked"})
default ExtendedAttributesBuilder putAll(Attributes attributes) {
if (attributes == null) {
return this;
}
attributes.forEach((key, value) -> put((AttributeKey<Object>) key, value));
return this;
}
/**
* Puts all the provided attributes into this Builder.
*
* @return this Builder
*/
@SuppressWarnings({"unchecked"})
default ExtendedAttributesBuilder putAll(ExtendedAttributes attributes) {
if (attributes == null) {
return this;
}
attributes.forEach((key, value) -> put((ExtendedAttributeKey<Object>) key, value));
return this;
}
/**
* Remove all attributes where {@link AttributeKey#getKey()} and {@link AttributeKey#getType()}
* match the {@code key}.
*
* @return this Builder
*/
default <T> ExtendedAttributesBuilder remove(AttributeKey<T> key) {
return remove(ExtendedAttributeKey.fromAttributeKey(key));
}
/**
* Remove all attributes where {@link ExtendedAttributeKey#getKey()} and {@link
* ExtendedAttributeKey#getType()} match the {@code key}.
*
* @return this Builder
*/
default <T> ExtendedAttributesBuilder remove(ExtendedAttributeKey<T> key) {
if (key == null || key.getKey().isEmpty()) {
return this;
}
return removeIf(
entryKey ->
key.getKey().equals(entryKey.getKey()) && key.getType().equals(entryKey.getType()));
}
/**
* Remove all attributes that satisfy the given predicate. Errors or runtime exceptions thrown by
* the predicate are relayed to the caller.
*
* @return this Builder
*/
ExtendedAttributesBuilder removeIf(Predicate<ExtendedAttributeKey<?>> filter);
}

View File

@ -1,37 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.incubator.config;
import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe;
/**
* A registry for accessing declarative configuration.
*
* <p>The name <i>Provider</i> is for consistency with other languages and it is <b>NOT</b> loaded
* using reflection.
*
* <p>See {@link InstrumentationConfigUtil} for convenience methods for extracting config from
* {@link ConfigProvider}.
*/
@ThreadSafe
public interface ConfigProvider {
/**
* Returns the {@link DeclarativeConfigProperties} corresponding to <a
* href="https://github.com/open-telemetry/opentelemetry-configuration/blob/main/schema/instrumentation.json">instrumentation
* config</a>, or {@code null} if unavailable.
*
* @return the instrumentation {@link DeclarativeConfigProperties}
*/
@Nullable
DeclarativeConfigProperties getInstrumentationConfig();
/** Returns a no-op {@link ConfigProvider}. */
static ConfigProvider noop() {
return () -> null;
}
}

View File

@ -1,22 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.incubator.config;
/** An exception that is thrown when errors occur with declarative configuration. */
public final class DeclarativeConfigException extends RuntimeException {
private static final long serialVersionUID = 3036584181551130522L;
/** Create a new configuration exception with specified {@code message} and without a cause. */
public DeclarativeConfigException(String message) {
super(message);
}
/** Create a new configuration exception with specified {@code message} and {@code cause}. */
public DeclarativeConfigException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@ -1,126 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.incubator.config;
import static java.util.stream.Collectors.toList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.BiFunction;
import javax.annotation.Nullable;
final class DeclarativeConfigPropertyUtil {
private DeclarativeConfigPropertyUtil() {}
private static final List<BiFunction<String, DeclarativeConfigProperties, Object>>
valueResolvers =
Arrays.asList(
DeclarativeConfigPropertyUtil::getString,
DeclarativeConfigPropertyUtil::getBoolean,
DeclarativeConfigPropertyUtil::getLong,
DeclarativeConfigPropertyUtil::getDouble,
DeclarativeConfigPropertyUtil::getStringList,
DeclarativeConfigPropertyUtil::getBooleanList,
DeclarativeConfigPropertyUtil::getLongList,
DeclarativeConfigPropertyUtil::getDoubleList,
DeclarativeConfigPropertyUtil::getStringList,
DeclarativeConfigPropertyUtil::getStructuredList,
DeclarativeConfigPropertyUtil::getStructured);
static Map<String, Object> toMap(DeclarativeConfigProperties declarativeConfigProperties) {
Set<String> propertyKeys = declarativeConfigProperties.getPropertyKeys();
Map<String, Object> result = new HashMap<>(propertyKeys.size());
for (String key : declarativeConfigProperties.getPropertyKeys()) {
result.put(key, resolveValue(key, declarativeConfigProperties));
}
return result;
}
@Nullable
private static Object resolveValue(
String key, DeclarativeConfigProperties declarativeConfigProperties) {
for (int i = 0; i < valueResolvers.size(); i++) {
try {
Object value = valueResolvers.get(i).apply(key, declarativeConfigProperties);
if (value != null) {
return value;
}
} catch (DeclarativeConfigException e) {
// Ignore and continue
}
}
return null;
}
@Nullable
private static Object getString(
String key, DeclarativeConfigProperties declarativeConfigProperties) {
return declarativeConfigProperties.getString(key);
}
@Nullable
private static Object getBoolean(
String key, DeclarativeConfigProperties declarativeConfigProperties) {
return declarativeConfigProperties.getBoolean(key);
}
@Nullable
private static Object getLong(
String key, DeclarativeConfigProperties declarativeConfigProperties) {
return declarativeConfigProperties.getLong(key);
}
@Nullable
private static Object getDouble(
String key, DeclarativeConfigProperties declarativeConfigProperties) {
return declarativeConfigProperties.getDouble(key);
}
@Nullable
private static Object getStringList(
String key, DeclarativeConfigProperties declarativeConfigProperties) {
return declarativeConfigProperties.getScalarList(key, String.class);
}
@Nullable
private static Object getBooleanList(
String key, DeclarativeConfigProperties declarativeConfigProperties) {
return declarativeConfigProperties.getScalarList(key, Boolean.class);
}
@Nullable
private static Object getLongList(
String key, DeclarativeConfigProperties declarativeConfigProperties) {
return declarativeConfigProperties.getScalarList(key, Long.class);
}
@Nullable
private static Object getDoubleList(
String key, DeclarativeConfigProperties declarativeConfigProperties) {
return declarativeConfigProperties.getScalarList(key, Double.class);
}
@Nullable
private static Object getStructuredList(
String key, DeclarativeConfigProperties declarativeConfigProperties) {
return Optional.ofNullable(declarativeConfigProperties.getStructuredList(key))
.map(list -> list.stream().map(DeclarativeConfigPropertyUtil::toMap).collect(toList()))
.orElse(null);
}
@Nullable
private static Object getStructured(
String key, DeclarativeConfigProperties declarativeConfigProperties) {
return Optional.ofNullable(declarativeConfigProperties.getStructured(key))
.map(DeclarativeConfigPropertyUtil::toMap)
.orElse(null);
}
}

View File

@ -1,63 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.incubator.config;
import io.opentelemetry.api.GlobalOpenTelemetry;
import java.util.concurrent.atomic.AtomicReference;
import javax.annotation.Nullable;
/**
* This class provides a temporary global accessor for {@link ConfigProvider} until the
* instrumentation config API is marked stable. It will eventually be merged into {@link
* GlobalOpenTelemetry}.
*/
// We intentionally assign to be used for error reporting.
@SuppressWarnings("StaticAssignmentOfThrowable")
public final class GlobalConfigProvider {
private static final AtomicReference<ConfigProvider> instance =
new AtomicReference<>(ConfigProvider.noop());
@SuppressWarnings("NonFinalStaticField")
@Nullable
private static volatile Throwable setInstanceCaller;
private GlobalConfigProvider() {}
/** Returns the globally registered {@link ConfigProvider}. */
// instance cannot be set to null
@SuppressWarnings("NullAway")
public static ConfigProvider get() {
return instance.get();
}
/**
* Sets the global {@link ConfigProvider}. Future calls to {@link #get()} will return the provided
* {@link ConfigProvider} instance. This should be called once as early as possible in your
* application initialization logic.
*
* @throws IllegalStateException when called more than once
*/
public static void set(ConfigProvider configProvider) {
boolean changed = instance.compareAndSet(ConfigProvider.noop(), configProvider);
if (!changed && (configProvider != ConfigProvider.noop())) {
throw new IllegalStateException(
"GlobalConfigProvider.set has already been called. GlobalConfigProvider.set "
+ "must be called only once before any calls to GlobalConfigProvider.get. "
+ "Previous invocation set to cause of this exception.",
setInstanceCaller);
}
setInstanceCaller = new Throwable();
}
/**
* Unsets the global {@link ConfigProvider}. This is only meant to be used from tests which need
* to reconfigure {@link ConfigProvider}.
*/
public static void resetForTest() {
instance.set(ConfigProvider.noop());
}
}

View File

@ -1,197 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.incubator.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import javax.annotation.Nullable;
/**
* A collection of convenience methods to extract instrumentation config from {@link
* ConfigProvider#getInstrumentationConfig()}.
*/
public class InstrumentationConfigUtil {
/**
* Return a map representation of the peer service map entries in {@code
* .instrumentation.general.peer.service_mapping}, or null if none is configured.
*
* @throws DeclarativeConfigException if an unexpected type is encountered accessing the property
*/
@Nullable
public static Map<String, String> peerServiceMapping(ConfigProvider configProvider) {
List<DeclarativeConfigProperties> serviceMappingList =
getOrNull(
configProvider,
config -> config.getStructuredList("service_mapping"),
"general",
"peer");
if (serviceMappingList == null) {
return null;
}
Map<String, String> serviceMapping = new LinkedHashMap<>();
serviceMappingList.forEach(
entry -> {
String peer = entry.getString("peer");
String service = entry.getString("service");
if (peer != null && service != null) {
serviceMapping.put(peer, service);
}
});
return serviceMapping.isEmpty() ? null : serviceMapping;
}
/**
* Return {@code .instrumentation.general.http.client.request_captured_headers}, or null if none
* is configured.
*
* @throws DeclarativeConfigException if an unexpected type is encountered accessing the property
*/
@Nullable
public static List<String> httpClientRequestCapturedHeaders(ConfigProvider configProvider) {
return getOrNull(
configProvider,
config -> config.getScalarList("request_captured_headers", String.class),
"general",
"http",
"client");
}
/**
* Return {@code .instrumentation.general.http.client.response_captured_headers}, or null if none
* is configured.
*
* @throws DeclarativeConfigException if an unexpected type is encountered accessing the property
*/
@Nullable
public static List<String> httpClientResponseCapturedHeaders(ConfigProvider configProvider) {
return getOrNull(
configProvider,
config -> config.getScalarList("response_captured_headers", String.class),
"general",
"http",
"client");
}
/**
* Return {@code .instrumentation.general.http.server.request_captured_headers}, or null if none
* is configured.
*
* @throws DeclarativeConfigException if an unexpected type is encountered accessing the property
*/
@Nullable
public static List<String> httpServerRequestCapturedHeaders(ConfigProvider configProvider) {
return getOrNull(
configProvider,
config -> config.getScalarList("request_captured_headers", String.class),
"general",
"http",
"server");
}
/**
* Return {@code .instrumentation.general.http.server.response_captured_headers}, or null if none
* is configured.
*
* @throws DeclarativeConfigException if an unexpected type is encountered accessing the property
*/
@Nullable
public static List<String> httpServerResponseCapturedHeaders(ConfigProvider configProvider) {
return getOrNull(
configProvider,
config -> config.getScalarList("response_captured_headers", String.class),
"general",
"http",
"server");
}
/**
* Return {@code .instrumentation.java.<instrumentationName>}, or null if none is configured.
*
* @throws DeclarativeConfigException if an unexpected type is encountered accessing the property
*/
@Nullable
public static DeclarativeConfigProperties javaInstrumentationConfig(
ConfigProvider configProvider, String instrumentationName) {
return getOrNull(configProvider, config -> config.getStructured(instrumentationName), "java");
}
/**
* Walk down the {@code segments} of {@link ConfigProvider#getInstrumentationConfig()} and call
* {@code accessor} on the terminal node. Returns null if {@link
* ConfigProvider#getInstrumentationConfig()} is null, or if null is encountered walking the
* {@code segments}, or if {@code accessor} returns null.
*
* <p>See other methods in {@link InstrumentationConfigUtil} for usage examples.
*/
@Nullable
public static <T> T getOrNull(
ConfigProvider configProvider,
Function<DeclarativeConfigProperties, T> accessor,
String... segments) {
DeclarativeConfigProperties config = configProvider.getInstrumentationConfig();
if (config == null) {
return null;
}
for (String segment : segments) {
config = config.getStructured(segment);
if (config == null) {
return null;
}
}
return accessor.apply(config);
}
private InstrumentationConfigUtil() {}
/**
* Return {@code .instrumentation.java.<instrumentationName>}, after converting it to the {@code
* modelType} using the {@code objectMapper}. If no configuration exists for the {@code
* instrumentationName}, returns {@code null}.
*
* <p>This method is a convenience method for a common instrumentation library workflow:
*
* <ul>
* <li>During initialization, an instrumentation library is given an {@link ConfigProvider} and
* must initialize according to the relevant config
* <li>It checks if the user has provided configuration for it, and if so...
* <li>It converts the configuration to an in-memory model representing all of its relevant
* properties
* <li>It initializes using the strongly typed in-memory model
* </ul>
*
* <p>Conversion is done using {@link ObjectMapper#convertValue(Object, Class)} from {@code
* com.fasterxml.jackson.databind}, and assumes the {@code modelType} is a POJO written /
* annotated to support jackson databinding.
*
* <p>NOTE: callers MUST add their own dependency on {@code
* com.fasterxml.jackson.core:jackson-databind}. This module's dependency is {@code compileOnly}
* since jackson is a large dependency that many users will not require. It's very possible to
* convert between {@link DeclarativeConfigProperties} (or a map representation from {@link
* DeclarativeConfigProperties#toMap(DeclarativeConfigProperties)}) and a target model type
* without jackson. This method is provided as an optional convenience method.
*
* @throws IllegalArgumentException if conversion fails. See {@link
* ObjectMapper#convertValue(Object, Class)} for details.
*/
@Nullable
public static <T> T getInstrumentationConfigModel(
ConfigProvider configProvider,
String instrumentationName,
ObjectMapper objectMapper,
Class<T> modelType) {
DeclarativeConfigProperties properties =
javaInstrumentationConfig(configProvider, instrumentationName);
if (properties == null) {
return null;
}
Map<String, Object> configPropertiesMap = DeclarativeConfigProperties.toMap(properties);
return objectMapper.convertValue(configPropertiesMap, modelType);
}
}

View File

@ -1,178 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.incubator.internal;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.AttributeType;
import io.opentelemetry.api.incubator.common.ExtendedAttributeKey;
import io.opentelemetry.api.incubator.common.ExtendedAttributeType;
import io.opentelemetry.api.internal.InternalAttributeKeyImpl;
import java.nio.charset.StandardCharsets;
import javax.annotation.Nullable;
/**
* This class is internal and is hence not for public use. Its APIs are unstable and can change at
* any time.
*/
public final class InternalExtendedAttributeKeyImpl<T> implements ExtendedAttributeKey<T> {
private final ExtendedAttributeType type;
private final String key;
private final int hashCode;
@Nullable private byte[] keyUtf8;
@Nullable private AttributeKey<T> attributeKey;
private InternalExtendedAttributeKeyImpl(ExtendedAttributeType type, String key) {
if (type == null) {
throw new NullPointerException("Null type");
}
this.type = type;
if (key == null) {
throw new NullPointerException("Null key");
}
this.key = key;
this.hashCode = buildHashCode(type, key);
}
public static <T> ExtendedAttributeKey<T> create(
@Nullable String key, ExtendedAttributeType type) {
return new InternalExtendedAttributeKeyImpl<>(type, key != null ? key : "");
}
@Override
public ExtendedAttributeType getType() {
return type;
}
@Override
public String getKey() {
return key;
}
@Nullable
@Override
public AttributeKey<T> asAttributeKey() {
if (attributeKey == null) {
attributeKey = toAttributeKey(this);
}
return attributeKey;
}
/** Returns the key, encoded as UTF-8 bytes. */
public byte[] getKeyUtf8() {
byte[] keyUtf8 = this.keyUtf8;
if (keyUtf8 == null) {
keyUtf8 = key.getBytes(StandardCharsets.UTF_8);
this.keyUtf8 = keyUtf8;
}
return keyUtf8;
}
@Override
public boolean equals(@Nullable Object o) {
if (o == this) {
return true;
}
if (o instanceof InternalExtendedAttributeKeyImpl) {
InternalExtendedAttributeKeyImpl<?> that = (InternalExtendedAttributeKeyImpl<?>) o;
return this.type.equals(that.getType()) && this.key.equals(that.getKey());
}
return false;
}
@Override
public int hashCode() {
return hashCode;
}
@Override
public String toString() {
return key;
}
// this method exists to make EqualsVerifier happy
@SuppressWarnings("unused")
private int buildHashCode() {
return buildHashCode(type, key);
}
private static int buildHashCode(ExtendedAttributeType type, String key) {
int result = 1;
result *= 1000003;
result ^= type.hashCode();
result *= 1000003;
result ^= key.hashCode();
return result;
}
/**
* Return the equivalent {@link AttributeKey} for the {@link ExtendedAttributeKey}, or {@code
* null} if the {@link #getType()} has no equivalent {@link
* io.opentelemetry.api.common.AttributeType}.
*/
@Nullable
public static <T> AttributeKey<T> toAttributeKey(ExtendedAttributeKey<T> extendedAttributeKey) {
switch (extendedAttributeKey.getType()) {
case STRING:
return InternalAttributeKeyImpl.create(extendedAttributeKey.getKey(), AttributeType.STRING);
case BOOLEAN:
return InternalAttributeKeyImpl.create(
extendedAttributeKey.getKey(), AttributeType.BOOLEAN);
case LONG:
return InternalAttributeKeyImpl.create(extendedAttributeKey.getKey(), AttributeType.LONG);
case DOUBLE:
return InternalAttributeKeyImpl.create(extendedAttributeKey.getKey(), AttributeType.DOUBLE);
case STRING_ARRAY:
return InternalAttributeKeyImpl.create(
extendedAttributeKey.getKey(), AttributeType.STRING_ARRAY);
case BOOLEAN_ARRAY:
return InternalAttributeKeyImpl.create(
extendedAttributeKey.getKey(), AttributeType.BOOLEAN_ARRAY);
case LONG_ARRAY:
return InternalAttributeKeyImpl.create(
extendedAttributeKey.getKey(), AttributeType.LONG_ARRAY);
case DOUBLE_ARRAY:
return InternalAttributeKeyImpl.create(
extendedAttributeKey.getKey(), AttributeType.DOUBLE_ARRAY);
case EXTENDED_ATTRIBUTES:
return null;
}
throw new IllegalArgumentException(
"Unrecognized extendedAttributeKey type: " + extendedAttributeKey.getType());
}
/** Return the equivalent {@link ExtendedAttributeKey} for the {@link AttributeKey}. */
public static <T> ExtendedAttributeKey<T> toExtendedAttributeKey(AttributeKey<T> attributeKey) {
switch (attributeKey.getType()) {
case STRING:
return InternalExtendedAttributeKeyImpl.create(
attributeKey.getKey(), ExtendedAttributeType.STRING);
case BOOLEAN:
return InternalExtendedAttributeKeyImpl.create(
attributeKey.getKey(), ExtendedAttributeType.BOOLEAN);
case LONG:
return InternalExtendedAttributeKeyImpl.create(
attributeKey.getKey(), ExtendedAttributeType.LONG);
case DOUBLE:
return InternalExtendedAttributeKeyImpl.create(
attributeKey.getKey(), ExtendedAttributeType.DOUBLE);
case STRING_ARRAY:
return InternalExtendedAttributeKeyImpl.create(
attributeKey.getKey(), ExtendedAttributeType.STRING_ARRAY);
case BOOLEAN_ARRAY:
return InternalExtendedAttributeKeyImpl.create(
attributeKey.getKey(), ExtendedAttributeType.BOOLEAN_ARRAY);
case LONG_ARRAY:
return InternalExtendedAttributeKeyImpl.create(
attributeKey.getKey(), ExtendedAttributeType.LONG_ARRAY);
case DOUBLE_ARRAY:
return InternalExtendedAttributeKeyImpl.create(
attributeKey.getKey(), ExtendedAttributeType.DOUBLE_ARRAY);
}
throw new IllegalArgumentException("Unrecognized attributeKey type: " + attributeKey.getType());
}
}

View File

@ -7,13 +7,12 @@ package io.opentelemetry.api.incubator.logs;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Value;
import io.opentelemetry.api.incubator.common.ExtendedAttributeKey;
import io.opentelemetry.api.logs.LogRecordBuilder;
import io.opentelemetry.api.logs.Logger;
import io.opentelemetry.api.logs.Severity;
import io.opentelemetry.context.Context;
import java.time.Instant;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nullable;
class ExtendedDefaultLogger implements ExtendedLogger {
@ -27,11 +26,6 @@ class ExtendedDefaultLogger implements ExtendedLogger {
return INSTANCE;
}
@Override
public boolean isEnabled(Severity severity, Context context) {
return false;
}
@Override
public ExtendedLogRecordBuilder logRecordBuilder() {
return NOOP_LOG_RECORD_BUILDER;
@ -47,62 +41,52 @@ class ExtendedDefaultLogger implements ExtendedLogger {
}
@Override
public ExtendedLogRecordBuilder setException(Throwable throwable) {
public LogRecordBuilder setTimestamp(long timestamp, TimeUnit unit) {
return this;
}
@Override
public <T> ExtendedLogRecordBuilder setAttribute(ExtendedAttributeKey<T> key, T value) {
public LogRecordBuilder setTimestamp(Instant instant) {
return this;
}
@Override
public <T> ExtendedLogRecordBuilder setAttribute(AttributeKey<T> key, @Nullable T value) {
public LogRecordBuilder setObservedTimestamp(long timestamp, TimeUnit unit) {
return this;
}
@Override
public ExtendedLogRecordBuilder setTimestamp(long timestamp, TimeUnit unit) {
public LogRecordBuilder setObservedTimestamp(Instant instant) {
return this;
}
@Override
public ExtendedLogRecordBuilder setTimestamp(Instant instant) {
public LogRecordBuilder setContext(Context context) {
return this;
}
@Override
public ExtendedLogRecordBuilder setObservedTimestamp(long timestamp, TimeUnit unit) {
public LogRecordBuilder setSeverity(Severity severity) {
return this;
}
@Override
public ExtendedLogRecordBuilder setObservedTimestamp(Instant instant) {
public LogRecordBuilder setSeverityText(String severityText) {
return this;
}
@Override
public ExtendedLogRecordBuilder setContext(Context context) {
public LogRecordBuilder setBody(String body) {
return this;
}
@Override
public ExtendedLogRecordBuilder setSeverity(Severity severity) {
public LogRecordBuilder setBody(Value<?> body) {
return this;
}
@Override
public ExtendedLogRecordBuilder setSeverityText(String severityText) {
return this;
}
@Override
public ExtendedLogRecordBuilder setBody(String body) {
return this;
}
@Override
public ExtendedLogRecordBuilder setBody(Value<?> body) {
public <T> LogRecordBuilder setAttribute(AttributeKey<T> key, T value) {
return this;
}

View File

@ -5,134 +5,18 @@
package io.opentelemetry.api.incubator.logs;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.common.Value;
import io.opentelemetry.api.incubator.common.ExtendedAttributeKey;
import io.opentelemetry.api.incubator.common.ExtendedAttributes;
import io.opentelemetry.api.logs.LogRecordBuilder;
import io.opentelemetry.api.logs.Severity;
import io.opentelemetry.context.Context;
import java.time.Instant;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nullable;
/** Extended {@link LogRecordBuilder} with experimental APIs. */
public interface ExtendedLogRecordBuilder extends LogRecordBuilder {
// keep this class even if it is empty, since experimental methods may be added in the future.
/** {@inheritDoc} */
@Override
ExtendedLogRecordBuilder setTimestamp(long timestamp, TimeUnit unit);
/** {@inheritDoc} */
@Override
ExtendedLogRecordBuilder setTimestamp(Instant instant);
/** {@inheritDoc} */
@Override
ExtendedLogRecordBuilder setObservedTimestamp(long timestamp, TimeUnit unit);
/** {@inheritDoc} */
@Override
ExtendedLogRecordBuilder setObservedTimestamp(Instant instant);
/** {@inheritDoc} */
@Override
ExtendedLogRecordBuilder setContext(Context context);
/** {@inheritDoc} */
@Override
ExtendedLogRecordBuilder setSeverity(Severity severity);
/** {@inheritDoc} */
@Override
ExtendedLogRecordBuilder setSeverityText(String severityText);
/** {@inheritDoc} */
@Override
ExtendedLogRecordBuilder setBody(String body);
/** {@inheritDoc} */
@Override
default ExtendedLogRecordBuilder setBody(Value<?> body) {
setBody(body.asString());
return this;
}
/**
* Sets the event name, which identifies the class / type of the Event.
*
* <p>This name should uniquely identify the event structure (both attributes and body). A log
* record with a non-empty event name is an Event.
*/
@Override
ExtendedLogRecordBuilder setEventName(String eventName);
/**
* {@inheritDoc}
*
* <p>NOTE: all standard {@link AttributeKey}-value pairs can also be represented as {@link
* ExtendedAttributeKey}-value pairs, but not all {@link ExtendedAttributeKey}-value pairs can be
* represented as standard {@link AttributeKey}-value pairs. From the standpoint of the emitted
* log record, there is no difference between adding attributes using the standard or extended
* attribute APIs.
*/
@SuppressWarnings("unchecked")
@Override
default ExtendedLogRecordBuilder setAllAttributes(Attributes attributes) {
if (attributes == null || attributes.isEmpty()) {
return this;
}
attributes.forEach(
(attributeKey, value) -> setAttribute((AttributeKey<Object>) attributeKey, value));
return this;
}
/**
* Sets attributes. If the {@link LogRecordBuilder} previously contained a mapping for any of the
* keys, the old values are replaced by the specified values.
*
* <p>NOTE: all standard {@link AttributeKey}-value pairs can also be represented as {@link
* ExtendedAttributeKey}-value pairs, but not all {@link ExtendedAttributeKey}-value pairs can be
* represented as standard {@link AttributeKey}-value pairs. From the standpoint of the emitted
* log record, there is no difference between adding attributes using the standard or extended
* attribute APIs.
*/
@SuppressWarnings("unchecked")
default ExtendedLogRecordBuilder setAllAttributes(ExtendedAttributes attributes) {
if (attributes == null || attributes.isEmpty()) {
return this;
}
attributes.forEach(
(attributeKey, value) -> setAttribute((ExtendedAttributeKey<Object>) attributeKey, value));
return this;
}
/**
* {@inheritDoc}
*
* <p>NOTE: all standard {@link AttributeKey}-value pairs can also be represented as {@link
* ExtendedAttributeKey}-value pairs, but not all {@link ExtendedAttributeKey}-value pairs can be
* represented as standard {@link AttributeKey}-value pairs. From the standpoint of the emitted
* log record, there is no difference between adding attributes using the standard or extended
* attribute APIs.
*/
@Override
<T> ExtendedLogRecordBuilder setAttribute(AttributeKey<T> key, @Nullable T value);
/**
* Set an attribute.
*
* <p>NOTE: all standard {@link AttributeKey}-value pairs can also be represented as {@link
* ExtendedAttributeKey}-value pairs, but not all {@link ExtendedAttributeKey}-value pairs can be
* represented as standard {@link AttributeKey}-value pairs. From the standpoint of the emitted
* log record, there is no difference between adding attributes using the standard or extended
* attribute APIs.
*/
<T> ExtendedLogRecordBuilder setAttribute(ExtendedAttributeKey<T> key, T value);
/** Set standard {@code exception.*} attributes based on the {@code throwable}. */
ExtendedLogRecordBuilder setException(Throwable throwable);
}

View File

@ -6,39 +6,19 @@
package io.opentelemetry.api.incubator.logs;
import io.opentelemetry.api.logs.Logger;
import io.opentelemetry.api.logs.Severity;
import io.opentelemetry.context.Context;
/** Extended {@link Logger} with experimental APIs. */
public interface ExtendedLogger extends Logger {
/**
* Returns {@code true} if the logger is enabled for the given {@code context} and {@code
* severity}.
* Returns {@code true} if the logger is enabled.
*
* <p>This allows callers to avoid unnecessary compute when nothing is consuming the data. Because
* the response is subject to change over the application, callers should call this before each
* call to {@link #logRecordBuilder()}.
*/
default boolean isEnabled(Severity severity, Context context) {
return true;
}
/** Overload of {@link #isEnabled(Severity, Context)} assuming {@link Context#current()}. */
default boolean isEnabled(Severity severity) {
return isEnabled(severity, Context.current());
}
/**
* Overload of {@link #isEnabled(Severity, Context)} assuming {@link
* Severity#UNDEFINED_SEVERITY_NUMBER} and {@link Context#current()}.
*
* @deprecated for removal after 1.55.0. Use {@link #isEnabled(Severity, Context)} or {@link
* #isEnabled(Severity)} instead.
*/
@Deprecated
default boolean isEnabled() {
return isEnabled(Severity.UNDEFINED_SEVERITY_NUMBER);
return true;
}
@Override

View File

@ -94,11 +94,6 @@ class ExtendedDefaultMeter implements Meter {
private ExtendedDefaultMeter() {}
private static class NoopLongCounter implements ExtendedLongCounter {
@Override
public boolean isEnabled() {
return false;
}
@Override
public void add(long value, Attributes attributes, Context context) {}
@ -110,11 +105,6 @@ class ExtendedDefaultMeter implements Meter {
}
private static class NoopDoubleCounter implements ExtendedDoubleCounter {
@Override
public boolean isEnabled() {
return false;
}
@Override
public void add(double value, Attributes attributes, Context context) {}
@ -196,11 +186,6 @@ class ExtendedDefaultMeter implements Meter {
}
private static class NoopLongUpDownCounter implements ExtendedLongUpDownCounter {
@Override
public boolean isEnabled() {
return false;
}
@Override
public void add(long value, Attributes attributes, Context context) {}
@ -212,11 +197,6 @@ class ExtendedDefaultMeter implements Meter {
}
private static class NoopDoubleUpDownCounter implements ExtendedDoubleUpDownCounter {
@Override
public boolean isEnabled() {
return false;
}
@Override
public void add(double value, Attributes attributes, Context context) {}
@ -301,11 +281,6 @@ class ExtendedDefaultMeter implements Meter {
}
private static class NoopDoubleHistogram implements ExtendedDoubleHistogram {
@Override
public boolean isEnabled() {
return false;
}
@Override
public void record(double value, Attributes attributes, Context context) {}
@ -317,11 +292,6 @@ class ExtendedDefaultMeter implements Meter {
}
private static class NoopLongHistogram implements ExtendedLongHistogram {
@Override
public boolean isEnabled() {
return false;
}
@Override
public void record(long value, Attributes attributes, Context context) {}
@ -415,11 +385,6 @@ class ExtendedDefaultMeter implements Meter {
}
private static class NoopDoubleGauge implements ExtendedDoubleGauge {
@Override
public boolean isEnabled() {
return false;
}
@Override
public void set(double value) {}
@ -461,11 +426,6 @@ class ExtendedDefaultMeter implements Meter {
}
private static class NoopLongGauge implements ExtendedLongGauge {
@Override
public boolean isEnabled() {
return false;
}
@Override
public void set(long value) {}

View File

@ -31,11 +31,6 @@ final class ExtendedDefaultTracer implements ExtendedTracer {
return INSTANCE;
}
@Override
public boolean isEnabled() {
return false;
}
@Override
public ExtendedSpanBuilder spanBuilder(String spanName) {
return NoopSpanBuilder.create();

View File

@ -1,20 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.incubator;
import static org.assertj.core.api.Assertions.assertThat;
import io.opentelemetry.api.incubator.config.ConfigProvider;
import org.junit.jupiter.api.Test;
class ConfigProviderTest {
@Test
void noopEquality() {
ConfigProvider noop = ConfigProvider.noop();
assertThat(ConfigProvider.noop()).isSameAs(noop);
}
}

View File

@ -1,85 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.incubator.common;
import static org.assertj.core.api.Assertions.assertThat;
import io.opentelemetry.api.common.AttributeKey;
import java.util.stream.Stream;
import javax.annotation.Nullable;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
public class ExtendedAttributeKeyTest {
@ParameterizedTest
@MethodSource("attributeKeyArgs")
void test(
ExtendedAttributeKey<?> key,
String expectedKey,
ExtendedAttributeType expectedType,
@Nullable AttributeKey<?> expectedAttributeKey) {
assertThat(key.getKey()).isEqualTo(expectedKey);
assertThat(key.getType()).isEqualTo(expectedType);
assertThat(key.asAttributeKey()).isEqualTo(expectedAttributeKey);
if (expectedAttributeKey != null) {
ExtendedAttributeKey<?> extendedAttributeKey =
ExtendedAttributeKey.fromAttributeKey(expectedAttributeKey);
assertThat(extendedAttributeKey).isEqualTo(key);
}
}
private static Stream<Arguments> attributeKeyArgs() {
return Stream.of(
Arguments.of(
ExtendedAttributeKey.stringKey("key"),
"key",
ExtendedAttributeType.STRING,
AttributeKey.stringKey("key")),
Arguments.of(
ExtendedAttributeKey.booleanKey("key"),
"key",
ExtendedAttributeType.BOOLEAN,
AttributeKey.booleanKey("key")),
Arguments.of(
ExtendedAttributeKey.longKey("key"),
"key",
ExtendedAttributeType.LONG,
AttributeKey.longKey("key")),
Arguments.of(
ExtendedAttributeKey.doubleKey("key"),
"key",
ExtendedAttributeType.DOUBLE,
AttributeKey.doubleKey("key")),
Arguments.of(
ExtendedAttributeKey.stringArrayKey("key"),
"key",
ExtendedAttributeType.STRING_ARRAY,
AttributeKey.stringArrayKey("key")),
Arguments.of(
ExtendedAttributeKey.booleanArrayKey("key"),
"key",
ExtendedAttributeType.BOOLEAN_ARRAY,
AttributeKey.booleanArrayKey("key")),
Arguments.of(
ExtendedAttributeKey.longArrayKey("key"),
"key",
ExtendedAttributeType.LONG_ARRAY,
AttributeKey.longArrayKey("key")),
Arguments.of(
ExtendedAttributeKey.doubleArrayKey("key"),
"key",
ExtendedAttributeType.DOUBLE_ARRAY,
AttributeKey.doubleArrayKey("key")),
Arguments.of(
ExtendedAttributeKey.extendedAttributesKey("key"),
"key",
ExtendedAttributeType.EXTENDED_ATTRIBUTES,
null));
}
}

View File

@ -1,360 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.incubator.common;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import com.google.common.collect.ImmutableMap;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
class ExtendedAttributesTest {
@ParameterizedTest
@MethodSource("attributesArgs")
void get_ExtendedAttributeKey(
ExtendedAttributes extendedAttributes, Map<String, Object> expectedMap) {
expectedMap.forEach(
(key, value) -> {
ExtendedAttributeKey<?> extendedAttributeKey = getKey(key, value);
Object actualValue = extendedAttributes.get(extendedAttributeKey);
if (actualValue instanceof ExtendedAttributes) {
Map<String, Object> mapValue = toMap((ExtendedAttributes) actualValue);
actualValue = mapValue;
}
assertThat(actualValue)
.describedAs(key + "(" + extendedAttributeKey.getType() + ")")
.isEqualTo(value);
});
}
@ParameterizedTest
@MethodSource("attributesArgs")
void get_AttributeKey(ExtendedAttributes extendedAttributes, Map<String, Object> expectedMap) {
expectedMap.forEach(
(key, value) -> {
ExtendedAttributeKey<?> extendedAttributeKey = getKey(key, value);
AttributeKey<?> attributeKey = extendedAttributeKey.asAttributeKey();
// Skip attribute keys which cannot be represented as AttributeKey
if (attributeKey == null) {
return;
}
Object actualValue = extendedAttributes.get(attributeKey);
assertThat(actualValue)
.describedAs(key + "(" + attributeKey.getType() + ")")
.isEqualTo(value);
});
}
@ParameterizedTest
@MethodSource("attributesArgs")
void forEach(ExtendedAttributes extendedAttributes, Map<String, Object> expectedMap) {
// toMap uses .forEach to convert
Map<String, Object> seenEntries = toMap(extendedAttributes);
assertThat(seenEntries).isEqualTo(expectedMap);
}
@ParameterizedTest
@MethodSource("attributesArgs")
void size(ExtendedAttributes extendedAttributes, Map<String, Object> expectedMap) {
assertThat(extendedAttributes.size()).isEqualTo(expectedMap.size());
}
@ParameterizedTest
@MethodSource("attributesArgs")
void isEmpty(ExtendedAttributes extendedAttributes, Map<String, Object> expectedMap) {
assertThat(extendedAttributes.isEmpty()).isEqualTo(expectedMap.isEmpty());
}
@ParameterizedTest
@MethodSource("attributesArgs")
void asMap(ExtendedAttributes extendedAttributes, Map<String, Object> expectedMap) {
assertEquals(extendedAttributes.asMap(), expectedMap);
}
@SuppressWarnings("unchecked")
private static void assertEquals(
Map<ExtendedAttributeKey<?>, Object> actual, Map<String, Object> expected) {
assertThat(actual.size()).isEqualTo(expected.size());
actual.forEach(
(key, value) -> {
if (key.getType() == ExtendedAttributeType.EXTENDED_ATTRIBUTES) {
assertEquals(
((ExtendedAttributes) value).asMap(),
(Map<String, Object>) expected.get(key.getKey()));
return;
}
assertThat(expected.get(key.getKey())).isEqualTo(value);
});
}
@ParameterizedTest
@MethodSource("attributesArgs")
void asAttributes(ExtendedAttributes extendedAttributes, Map<String, Object> expectedMap) {
Attributes attributes = extendedAttributes.asAttributes();
attributes.forEach(
(key, value) -> {
assertThat(value).isEqualTo(expectedMap.get(key.getKey()));
});
long expectedSize =
expectedMap.values().stream().filter(value -> !(value instanceof Map)).count();
assertThat(attributes.size()).isEqualTo(expectedSize);
}
@ParameterizedTest
@MethodSource("attributesArgs")
void toBuilder(ExtendedAttributes extendedAttributes, Map<String, Object> expectedMap) {
ExtendedAttributesBuilder builder = extendedAttributes.toBuilder();
builder.put("extraKey", "value");
ExtendedAttributes extendedAttributes1 = builder.build();
assertThat(extendedAttributes1.size()).isEqualTo(expectedMap.size() + 1);
ExtendedAttributes extendedAttributes2 =
extendedAttributes1.toBuilder().remove(ExtendedAttributeKey.stringKey("extraKey")).build();
assertThat(extendedAttributes2).isEqualTo(extendedAttributes);
assertThat(extendedAttributes2.size()).isEqualTo(expectedMap.size());
}
@ParameterizedTest
@MethodSource("attributesArgs")
void equalsAndHashcode(ExtendedAttributes extendedAttributes, Map<String, Object> expectedMap) {
ExtendedAttributes withExtraEntry =
extendedAttributes.toBuilder().put("extraKey", "value").build();
assertThat(extendedAttributes).isNotEqualTo(withExtraEntry);
assertThat(extendedAttributes.hashCode()).isNotEqualTo(withExtraEntry.hashCode());
ExtendedAttributes copy1 =
extendedAttributes.toBuilder().remove(ExtendedAttributeKey.stringKey("extraKey")).build();
assertThat(extendedAttributes).isEqualTo(copy1);
assertThat(extendedAttributes.hashCode()).isEqualTo(copy1.hashCode());
ExtendedAttributes copy2 = fromMap(expectedMap);
assertThat(extendedAttributes).isEqualTo(copy2);
assertThat(extendedAttributes.hashCode()).isEqualTo(copy2.hashCode());
}
@SuppressWarnings("unchecked")
private static ExtendedAttributes fromMap(Map<String, Object> map) {
ExtendedAttributesBuilder builder = ExtendedAttributes.builder();
map.forEach(
(key, value) -> {
ExtendedAttributeKey<?> extendedAttributeKey = getKey(key, value);
if (extendedAttributeKey.getType() == ExtendedAttributeType.EXTENDED_ATTRIBUTES) {
builder.put(
(ExtendedAttributeKey<ExtendedAttributes>) extendedAttributeKey,
fromMap((Map<String, Object>) value));
return;
}
putInBuilder((ExtendedAttributeKey<Object>) extendedAttributeKey, value, builder);
});
return builder.build();
}
private static void putInBuilder(
ExtendedAttributeKey<Object> key, Object value, ExtendedAttributesBuilder builder) {
builder.put(key, value);
}
private static Stream<Arguments> attributesArgs() {
return Stream.of(
// Single entry attributes
Arguments.of(ExtendedAttributes.builder().build(), Collections.emptyMap()),
Arguments.of(
ExtendedAttributes.builder().put("key", "value").build(),
ImmutableMap.builder().put("key", "value").build()),
Arguments.of(
ExtendedAttributes.builder().put("key", true).build(),
ImmutableMap.builder().put("key", true).build()),
Arguments.of(
ExtendedAttributes.builder().put("key", 1L).build(),
ImmutableMap.builder().put("key", 1L).build()),
Arguments.of(
ExtendedAttributes.builder().put("key", 1.1).build(),
ImmutableMap.builder().put("key", 1.1).build()),
Arguments.of(
ExtendedAttributes.builder().put("key", "value1", "value2").build(),
ImmutableMap.builder().put("key", Arrays.asList("value1", "value2")).build()),
Arguments.of(
ExtendedAttributes.builder().put("key", true, false).build(),
ImmutableMap.builder().put("key", Arrays.asList(true, false)).build()),
Arguments.of(
ExtendedAttributes.builder().put("key", 1L, 2L).build(),
ImmutableMap.builder().put("key", Arrays.asList(1L, 2L)).build()),
Arguments.of(
ExtendedAttributes.builder().put("key", 1.1, 2.2).build(),
ImmutableMap.builder().put("key", Arrays.asList(1.1, 2.2)).build()),
Arguments.of(
ExtendedAttributes.builder()
.put("key", ExtendedAttributes.builder().put("child", "value").build())
.build(),
ImmutableMap.builder()
.put("key", ImmutableMap.builder().put("child", "value").build())
.build()),
Arguments.of(
ExtendedAttributes.builder()
.put(ExtendedAttributeKey.stringKey("key"), "value")
.build(),
ImmutableMap.builder().put("key", "value").build()),
Arguments.of(
ExtendedAttributes.builder().put(ExtendedAttributeKey.booleanKey("key"), true).build(),
ImmutableMap.builder().put("key", true).build()),
Arguments.of(
ExtendedAttributes.builder().put(ExtendedAttributeKey.longKey("key"), 1L).build(),
ImmutableMap.builder().put("key", 1L).build()),
Arguments.of(
ExtendedAttributes.builder().put(ExtendedAttributeKey.doubleKey("key"), 1.1).build(),
ImmutableMap.builder().put("key", 1.1).build()),
Arguments.of(
ExtendedAttributes.builder()
.put(ExtendedAttributeKey.stringArrayKey("key"), Arrays.asList("value1", "value2"))
.build(),
ImmutableMap.builder().put("key", Arrays.asList("value1", "value2")).build()),
Arguments.of(
ExtendedAttributes.builder()
.put(ExtendedAttributeKey.booleanArrayKey("key"), Arrays.asList(true, false))
.build(),
ImmutableMap.builder().put("key", Arrays.asList(true, false)).build()),
Arguments.of(
ExtendedAttributes.builder()
.put(ExtendedAttributeKey.longArrayKey("key"), Arrays.asList(1L, 2L))
.build(),
ImmutableMap.builder().put("key", Arrays.asList(1L, 2L)).build()),
Arguments.of(
ExtendedAttributes.builder()
.put(ExtendedAttributeKey.doubleArrayKey("key"), Arrays.asList(1.1, 2.2))
.build(),
ImmutableMap.builder().put("key", Arrays.asList(1.1, 2.2)).build()),
Arguments.of(
ExtendedAttributes.builder()
.put(
ExtendedAttributeKey.extendedAttributesKey("key"),
ExtendedAttributes.builder().put("child", "value").build())
.build(),
ImmutableMap.builder()
.put("key", ImmutableMap.builder().put("child", "value").build())
.build()),
// Multiple entries
Arguments.of(
ExtendedAttributes.builder()
.put("key1", "value1")
.put("key2", "value2")
.put("key3", true)
.put("key4", 1L)
.put("key5", 1.1)
.put("key6", "value1", "value2")
.put("key7", true, false)
.put("key8", 1L, 2L)
.put("key9", 1.1, 2.2)
.put("key10", ExtendedAttributes.builder().put("child", "value").build())
.build(),
ImmutableMap.builder()
.put("key1", "value1")
.put("key2", "value2")
.put("key3", true)
.put("key4", 1L)
.put("key5", 1.1)
.put("key6", Arrays.asList("value1", "value2"))
.put("key7", Arrays.asList(true, false))
.put("key8", Arrays.asList(1L, 2L))
.put("key9", Arrays.asList(1.1, 2.2))
.put("key10", ImmutableMap.builder().put("child", "value").build())
.build()));
}
private static Map<String, Object> toMap(ExtendedAttributes extendedAttributes) {
Map<String, Object> map = new HashMap<>();
extendedAttributes.forEach(
(key, value) -> {
if (key.getType() == ExtendedAttributeType.EXTENDED_ATTRIBUTES) {
map.put(key.getKey(), toMap((ExtendedAttributes) value));
return;
}
map.put(key.getKey(), value);
});
return map;
}
private static ExtendedAttributeKey<?> getKey(String key, Object value) {
switch (getType(value)) {
case STRING:
return ExtendedAttributeKey.stringKey(key);
case BOOLEAN:
return ExtendedAttributeKey.booleanKey(key);
case LONG:
return ExtendedAttributeKey.longKey(key);
case DOUBLE:
return ExtendedAttributeKey.doubleKey(key);
case STRING_ARRAY:
return ExtendedAttributeKey.stringArrayKey(key);
case BOOLEAN_ARRAY:
return ExtendedAttributeKey.booleanArrayKey(key);
case LONG_ARRAY:
return ExtendedAttributeKey.longArrayKey(key);
case DOUBLE_ARRAY:
return ExtendedAttributeKey.doubleArrayKey(key);
case EXTENDED_ATTRIBUTES:
return ExtendedAttributeKey.extendedAttributesKey(key);
}
throw new IllegalArgumentException();
}
@SuppressWarnings("unchecked")
private static ExtendedAttributeType getType(Object value) {
if (value instanceof String) {
return ExtendedAttributeType.STRING;
}
if (value instanceof Boolean) {
return ExtendedAttributeType.BOOLEAN;
}
if ((value instanceof Long) || (value instanceof Integer)) {
return ExtendedAttributeType.LONG;
}
if ((value instanceof Double) || (value instanceof Float)) {
return ExtendedAttributeType.DOUBLE;
}
if (value instanceof List) {
List<Object> list = (List<Object>) value;
if (list.isEmpty()) {
throw new IllegalArgumentException("Empty list");
}
if (list.get(0) instanceof String) {
return ExtendedAttributeType.STRING_ARRAY;
}
if (list.get(0) instanceof Boolean) {
return ExtendedAttributeType.BOOLEAN_ARRAY;
}
if ((list.get(0) instanceof Long) || (list.get(0) instanceof Integer)) {
return ExtendedAttributeType.LONG_ARRAY;
}
if ((list.get(0) instanceof Double) || (list.get(0) instanceof Float)) {
return ExtendedAttributeType.DOUBLE_ARRAY;
}
}
if ((value instanceof Map)) {
return ExtendedAttributeType.EXTENDED_ATTRIBUTES;
}
throw new IllegalArgumentException("Unrecognized value type: " + value);
}
}

View File

@ -1,44 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.incubator.config;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
class GlobalConfigProviderTest {
@BeforeAll
static void beforeClass() {
GlobalConfigProvider.resetForTest();
}
@AfterEach
void after() {
GlobalConfigProvider.resetForTest();
}
@Test
void setAndGet() {
assertThat(GlobalConfigProvider.get()).isEqualTo(ConfigProvider.noop());
ConfigProvider configProvider = DeclarativeConfigProperties::empty;
GlobalConfigProvider.set(configProvider);
assertThat(GlobalConfigProvider.get()).isSameAs(configProvider);
}
@Test
void setThenSet() {
ConfigProvider configProvider = DeclarativeConfigProperties::empty;
GlobalConfigProvider.set(configProvider);
assertThatThrownBy(() -> GlobalConfigProvider.set(configProvider))
.isInstanceOf(IllegalStateException.class)
.hasMessageContaining("GlobalConfigProvider.set has already been called")
.hasStackTraceContaining("setThenSet");
}
}

View File

@ -1,170 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.incubator.config;
import static org.assertj.core.api.Assertions.assertThat;
import com.google.common.collect.ImmutableMap;
import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfiguration;
import io.opentelemetry.sdk.extension.incubator.fileconfig.SdkConfigProvider;
import io.opentelemetry.sdk.extension.incubator.fileconfig.YamlDeclarativeConfigProperties;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel;
import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import org.junit.jupiter.api.Test;
class InstrumentationConfigUtilTest {
/**
* See <a
* href="https://github.com/open-telemetry/opentelemetry-configuration/blob/main/examples/kitchen-sink.yaml">kitchen-sink.yaml</a>.
*/
private static final String kitchenSinkInstrumentationConfig =
"instrumentation/development:\n"
+ " general:\n"
+ " peer:\n"
+ " service_mapping:\n"
+ " - peer: 1.2.3.4\n"
+ " service: FooService\n"
+ " - peer: 2.3.4.5\n"
+ " service: BarService\n"
+ " http:\n"
+ " client:\n"
+ " request_captured_headers:\n"
+ " - client-request-header1\n"
+ " - client-request-header2\n"
+ " response_captured_headers:\n"
+ " - client-response-header1\n"
+ " - client-response-header2\n"
+ " server:\n"
+ " request_captured_headers:\n"
+ " - server-request-header1\n"
+ " - server-request-header2\n"
+ " response_captured_headers:\n"
+ " - server-response-header1\n"
+ " - server-response-header2\n"
+ " java:\n"
+ " example:\n"
+ " property: \"value\"";
private static final ConfigProvider kitchenSinkConfigProvider =
toConfigProvider(kitchenSinkInstrumentationConfig);
private static final ConfigProvider emptyInstrumentationConfigProvider =
toConfigProvider("instrumentation/development:\n");
private static final ConfigProvider emptyGeneralConfigProvider =
toConfigProvider("instrumentation/development:\n general:\n");
private static final ConfigProvider emptyHttpConfigProvider =
toConfigProvider("instrumentation/development:\n general:\n http:\n");
private static ConfigProvider toConfigProvider(String configYaml) {
OpenTelemetryConfigurationModel configuration =
DeclarativeConfiguration.parse(
new ByteArrayInputStream(configYaml.getBytes(StandardCharsets.UTF_8)));
return SdkConfigProvider.create(configuration);
}
@Test
void peerServiceMapping() {
assertThat(InstrumentationConfigUtil.peerServiceMapping(kitchenSinkConfigProvider))
.isEqualTo(ImmutableMap.of("1.2.3.4", "FooService", "2.3.4.5", "BarService"));
assertThat(InstrumentationConfigUtil.peerServiceMapping(emptyInstrumentationConfigProvider))
.isNull();
assertThat(InstrumentationConfigUtil.peerServiceMapping(emptyGeneralConfigProvider)).isNull();
assertThat(InstrumentationConfigUtil.peerServiceMapping(emptyHttpConfigProvider)).isNull();
}
@Test
void httpClientRequestCapturedHeaders() {
assertThat(
InstrumentationConfigUtil.httpClientRequestCapturedHeaders(kitchenSinkConfigProvider))
.isEqualTo(Arrays.asList("client-request-header1", "client-request-header2"));
assertThat(
InstrumentationConfigUtil.httpClientRequestCapturedHeaders(
emptyInstrumentationConfigProvider))
.isNull();
assertThat(
InstrumentationConfigUtil.httpClientRequestCapturedHeaders(emptyGeneralConfigProvider))
.isNull();
assertThat(InstrumentationConfigUtil.httpClientRequestCapturedHeaders(emptyHttpConfigProvider))
.isNull();
}
@Test
void httpClientResponseCapturedHeaders() {
assertThat(
InstrumentationConfigUtil.httpClientResponseCapturedHeaders(kitchenSinkConfigProvider))
.isEqualTo(Arrays.asList("client-response-header1", "client-response-header2"));
assertThat(
InstrumentationConfigUtil.httpClientResponseCapturedHeaders(
emptyInstrumentationConfigProvider))
.isNull();
assertThat(
InstrumentationConfigUtil.httpClientResponseCapturedHeaders(emptyGeneralConfigProvider))
.isNull();
assertThat(InstrumentationConfigUtil.httpClientResponseCapturedHeaders(emptyHttpConfigProvider))
.isNull();
}
@Test
void httpServerRequestCapturedHeaders() {
assertThat(
InstrumentationConfigUtil.httpServerRequestCapturedHeaders(kitchenSinkConfigProvider))
.isEqualTo(Arrays.asList("server-request-header1", "server-request-header2"));
assertThat(
InstrumentationConfigUtil.httpServerRequestCapturedHeaders(
emptyInstrumentationConfigProvider))
.isNull();
assertThat(
InstrumentationConfigUtil.httpServerRequestCapturedHeaders(emptyGeneralConfigProvider))
.isNull();
assertThat(InstrumentationConfigUtil.httpServerRequestCapturedHeaders(emptyHttpConfigProvider))
.isNull();
}
@Test
void httpServerResponseCapturedHeaders() {
assertThat(
InstrumentationConfigUtil.httpServerResponseCapturedHeaders(kitchenSinkConfigProvider))
.isEqualTo(Arrays.asList("server-response-header1", "server-response-header2"));
assertThat(
InstrumentationConfigUtil.httpServerResponseCapturedHeaders(
emptyInstrumentationConfigProvider))
.isNull();
assertThat(
InstrumentationConfigUtil.httpServerResponseCapturedHeaders(emptyGeneralConfigProvider))
.isNull();
assertThat(InstrumentationConfigUtil.httpServerResponseCapturedHeaders(emptyHttpConfigProvider))
.isNull();
}
@Test
void javaInstrumentationConfig() {
assertThat(
InstrumentationConfigUtil.javaInstrumentationConfig(
kitchenSinkConfigProvider, "example"))
.isNotNull()
.isInstanceOfSatisfying(
YamlDeclarativeConfigProperties.class,
exampleConfig ->
assertThat(DeclarativeConfigProperties.toMap(exampleConfig))
.isEqualTo(ImmutableMap.of("property", "value")));
assertThat(
InstrumentationConfigUtil.javaInstrumentationConfig(kitchenSinkConfigProvider, "foo"))
.isNull();
assertThat(
InstrumentationConfigUtil.javaInstrumentationConfig(
emptyInstrumentationConfigProvider, "example"))
.isNull();
assertThat(
InstrumentationConfigUtil.javaInstrumentationConfig(
emptyGeneralConfigProvider, "example"))
.isNull();
assertThat(
InstrumentationConfigUtil.javaInstrumentationConfig(emptyHttpConfigProvider, "example"))
.isNull();
}
}

View File

@ -10,9 +10,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import io.opentelemetry.api.common.Value;
import io.opentelemetry.api.logs.Logger;
import io.opentelemetry.api.logs.LoggerProvider;
import io.opentelemetry.api.logs.Severity;
import io.opentelemetry.api.testing.internal.AbstractDefaultLoggerTest;
import io.opentelemetry.context.Context;
import org.junit.jupiter.api.Test;
class ExtendedDefaultLoggerTest extends AbstractDefaultLoggerTest {
@ -28,18 +26,10 @@ class ExtendedDefaultLoggerTest extends AbstractDefaultLoggerTest {
}
@Test
@SuppressWarnings("deprecation") // testing deprecated code
void incubatingApiIsLoaded() {
Logger logger = LoggerProvider.noop().get("test");
assertThat(logger)
.isInstanceOfSatisfying(
ExtendedLogger.class,
extendedLogger -> {
assertThat(extendedLogger.isEnabled(Severity.ERROR, Context.current())).isFalse();
assertThat(extendedLogger.isEnabled(Severity.ERROR)).isFalse();
assertThat(extendedLogger.isEnabled()).isFalse();
});
assertThat(logger).isInstanceOf(ExtendedLogger.class);
ExtendedLogRecordBuilder builder = (ExtendedLogRecordBuilder) logger.logRecordBuilder();
assertThat(builder).isInstanceOf(ExtendedLogRecordBuilder.class);
assertThat(builder.setBody(Value.of(0))).isSameAs(builder);

View File

@ -9,31 +9,19 @@ import static io.opentelemetry.sdk.internal.ScopeConfiguratorBuilder.nameEquals;
import static io.opentelemetry.sdk.logs.internal.LoggerConfig.disabled;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.incubator.common.ExtendedAttributeKey;
import io.opentelemetry.api.incubator.common.ExtendedAttributes;
import io.opentelemetry.api.logs.Logger;
import io.opentelemetry.api.logs.Severity;
import io.opentelemetry.internal.testing.slf4j.SuppressLogger;
import io.opentelemetry.sdk.logs.SdkLoggerProvider;
import io.opentelemetry.sdk.logs.SdkLoggerProviderBuilder;
import io.opentelemetry.sdk.logs.data.internal.ExtendedLogRecordData;
import io.opentelemetry.sdk.logs.export.SimpleLogRecordProcessor;
import io.opentelemetry.sdk.logs.internal.SdkLoggerProviderUtil;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.testing.exporter.InMemoryLogRecordExporter;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import org.junit.jupiter.api.Test;
/** Demonstrating usage of extended Logs Bridge API. */
class ExtendedLogsBridgeApiUsageTest {
private static final java.util.logging.Logger logger =
java.util.logging.Logger.getLogger(ExtendedLogsBridgeApiUsageTest.class.getName());
@Test
void loggerEnabled() {
// Setup SdkLoggerProvider
@ -54,26 +42,24 @@ class ExtendedLogsBridgeApiUsageTest {
ExtendedLogger loggerB = (ExtendedLogger) loggerProvider.get("loggerB");
// Check if logger is enabled before emitting log and avoid unnecessary computation
if (loggerA.isEnabled(Severity.INFO)) {
if (loggerA.isEnabled()) {
loggerA
.logRecordBuilder()
.setSeverity(Severity.INFO)
.setBody("hello world!")
.setAllAttributes(Attributes.builder().put("result", flipCoin()).build())
.emit();
}
if (loggerB.isEnabled(Severity.INFO)) {
if (loggerB.isEnabled()) {
loggerB
.logRecordBuilder()
.setSeverity(Severity.INFO)
.setBody("hello world!")
.setAllAttributes(Attributes.builder().put("result", flipCoin()).build())
.emit();
}
// loggerA is enabled, loggerB is disabled
assertThat(loggerA.isEnabled(Severity.INFO)).isTrue();
assertThat(loggerB.isEnabled(Severity.INFO)).isFalse();
assertThat(loggerA.isEnabled()).isTrue();
assertThat(loggerB.isEnabled()).isFalse();
// Collected data only consists of logs from loggerA. Note, loggerB's logs would be
// omitted from the results even if logs were emitted. The check if enabled simply avoids
@ -90,148 +76,4 @@ class ExtendedLogsBridgeApiUsageTest {
private static String flipCoin() {
return random.nextBoolean() ? "heads" : "tails";
}
// Primitive keys
AttributeKey<String> strKey = AttributeKey.stringKey("acme.string");
AttributeKey<Long> longKey = AttributeKey.longKey("acme.long");
AttributeKey<Boolean> booleanKey = AttributeKey.booleanKey("acme.boolean");
AttributeKey<Double> doubleKey = AttributeKey.doubleKey("acme.double");
// Primitive array keys
AttributeKey<List<String>> strArrKey = AttributeKey.stringArrayKey("acme.string_array");
AttributeKey<List<Long>> longArrKey = AttributeKey.longArrayKey("acme.long_array");
AttributeKey<List<Boolean>> booleanArrKey = AttributeKey.booleanArrayKey("acme.boolean_array");
AttributeKey<List<Double>> doubleArrKey = AttributeKey.doubleArrayKey("acme.double_array");
// Extended keys
ExtendedAttributeKey<ExtendedAttributes> mapKey =
ExtendedAttributeKey.extendedAttributesKey("acme.map");
@Test
@SuppressLogger(ExtendedLogsBridgeApiUsageTest.class)
void extendedAttributesUsage() {
// Initialize from builder. Varargs style initialization (ExtendedAttributes.of(...) not
// supported.
ExtendedAttributes extendedAttributes =
ExtendedAttributes.builder()
.put(strKey, "value")
.put(longKey, 1L)
.put(booleanKey, true)
.put(doubleKey, 1.1)
.put(strArrKey, Arrays.asList("value1", "value2"))
.put(longArrKey, Arrays.asList(1L, 2L))
.put(booleanArrKey, Arrays.asList(true, false))
.put(doubleArrKey, Arrays.asList(1.1, 2.2))
.put(
mapKey,
ExtendedAttributes.builder().put("childStr", "value").put("childLong", 1L).build())
.build();
// Retrieval
assertThat(extendedAttributes.get(strKey)).isEqualTo("value");
assertThat(extendedAttributes.get(longKey)).isEqualTo(1);
assertThat(extendedAttributes.get(booleanKey)).isEqualTo(true);
assertThat(extendedAttributes.get(doubleKey)).isEqualTo(1.1);
assertThat(extendedAttributes.get(strArrKey)).isEqualTo(Arrays.asList("value1", "value2"));
assertThat(extendedAttributes.get(longArrKey)).isEqualTo(Arrays.asList(1L, 2L));
assertThat(extendedAttributes.get(booleanArrKey)).isEqualTo(Arrays.asList(true, false));
assertThat(extendedAttributes.get(doubleArrKey)).isEqualTo(Arrays.asList(1.1, 2.2));
assertThat(extendedAttributes.get(mapKey))
.isEqualTo(
ExtendedAttributes.builder().put("childStr", "value").put("childLong", 1L).build());
// Iteration
// Output:
// acme.boolean(BOOLEAN): true
// acme.boolean_array(BOOLEAN_ARRAY): [true, false]
// acme.double(DOUBLE): 1.1
// acme.double_array(DOUBLE_ARRAY): [1.1, 2.2]
// acme.long(LONG): 1
// acme.long_array(LONG_ARRAY): [1, 2]
// acme.map(EXTENDED_ATTRIBUTES): {childLong=1, childStr="value"}
// acme.string(STRING): value
// acme.string_array(STRING_ARRAY): [value1, value2]
extendedAttributes.forEach(
(extendedAttributeKey, object) ->
logger.info(
String.format(
"%s(%s): %s",
extendedAttributeKey.getKey(), extendedAttributeKey.getType(), object)));
}
@Test
@SuppressWarnings("deprecation") // testing deprecated code
void logRecordBuilder_ExtendedAttributes() {
InMemoryLogRecordExporter exporter = InMemoryLogRecordExporter.create();
SdkLoggerProvider loggerProvider =
SdkLoggerProvider.builder()
.addLogRecordProcessor(SimpleLogRecordProcessor.create(exporter))
.build();
Logger logger = loggerProvider.get("logger");
// Can set either standard or extended attributes on
((ExtendedLogRecordBuilder) logger.logRecordBuilder())
.setBody("message")
.setAttribute(strKey, "value")
.setAttribute(longKey, 1L)
.setAttribute(booleanKey, true)
.setAttribute(doubleKey, 1.1)
.setAttribute(strArrKey, Arrays.asList("value1", "value2"))
.setAttribute(longArrKey, Arrays.asList(1L, 2L))
.setAttribute(booleanArrKey, Arrays.asList(true, false))
.setAttribute(doubleArrKey, Arrays.asList(1.1, 2.2))
.setAttribute(
mapKey,
ExtendedAttributes.builder().put("childStr", "value").put("childLong", 1L).build())
.setAllAttributes(Attributes.builder().put("key1", "value").build())
.setAllAttributes(ExtendedAttributes.builder().put("key2", "value").build())
.emit();
assertThat(exporter.getFinishedLogRecordItems())
.satisfiesExactly(
logRecordData -> {
assertThat(logRecordData).isInstanceOf(ExtendedLogRecordData.class);
ExtendedLogRecordData extendedLogRecordData = (ExtendedLogRecordData) logRecordData;
// Optionally access standard attributes, which filters out any extended attribute
// types
assertThat(extendedLogRecordData.getAttributes())
.isEqualTo(
Attributes.builder()
.put(strKey, "value")
.put(longKey, 1L)
.put(booleanKey, true)
.put(doubleKey, 1.1)
.put(strArrKey, Arrays.asList("value1", "value2"))
.put(longArrKey, Arrays.asList(1L, 2L))
.put(booleanArrKey, Arrays.asList(true, false))
.put(doubleArrKey, Arrays.asList(1.1, 2.2))
.put("key1", "value")
.put("key2", "value")
.build());
// But preferably access and serialize full extended attributes
assertThat(extendedLogRecordData.getExtendedAttributes())
.isEqualTo(
ExtendedAttributes.builder()
.put(strKey, "value")
.put(longKey, 1L)
.put(booleanKey, true)
.put(doubleKey, 1.1)
.put(strArrKey, Arrays.asList("value1", "value2"))
.put(longArrKey, Arrays.asList(1L, 2L))
.put(booleanArrKey, Arrays.asList(true, false))
.put(doubleArrKey, Arrays.asList(1.1, 2.2))
.put(
mapKey,
ExtendedAttributes.builder()
.put("childStr", "value")
.put("childLong", 1L)
.build())
.put("key1", "value")
.put("key2", "value")
.build());
});
}
}

View File

@ -11,6 +11,7 @@ import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.api.metrics.MeterProvider;
import io.opentelemetry.api.testing.internal.AbstractDefaultMeterTest;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
class ExtendedDefaultMeterTest extends AbstractDefaultMeterTest {
@ -26,53 +27,44 @@ class ExtendedDefaultMeterTest extends AbstractDefaultMeterTest {
}
@Test
void incubatingApiIsLoaded() {
public void incubatingApiIsLoaded() {
Meter meter = MeterProvider.noop().get("test");
assertThat(meter).isSameAs(OpenTelemetry.noop().getMeter("test"));
assertThat(meter.gaugeBuilder("test").ofLongs()).isInstanceOf(ExtendedLongGaugeBuilder.class);
assertThat(meter.gaugeBuilder("test").ofLongs().build())
.isInstanceOfSatisfying(
ExtendedLongGauge.class, instrument -> assertThat(instrument.isEnabled()).isFalse());
assertThat(meter.gaugeBuilder("test")).isInstanceOf(ExtendedDoubleGaugeBuilder.class);
assertThat(meter.gaugeBuilder("test").build())
.isInstanceOfSatisfying(
ExtendedDoubleGauge.class, instrument -> assertThat(instrument.isEnabled()).isFalse());
Assertions.assertThat(meter.gaugeBuilder("test").ofLongs())
.isInstanceOf(ExtendedLongGaugeBuilder.class);
Assertions.assertThat(meter.gaugeBuilder("test").ofLongs().build())
.isInstanceOf(ExtendedLongGauge.class);
Assertions.assertThat(meter.gaugeBuilder("test"))
.isInstanceOf(ExtendedDoubleGaugeBuilder.class);
Assertions.assertThat(meter.gaugeBuilder("test").build())
.isInstanceOf(ExtendedDoubleGauge.class);
assertThat(meter.histogramBuilder("test").ofLongs())
Assertions.assertThat(meter.histogramBuilder("test").ofLongs())
.isInstanceOf(ExtendedLongHistogramBuilder.class);
assertThat(meter.histogramBuilder("test").ofLongs().build())
.isInstanceOfSatisfying(
ExtendedLongHistogram.class,
instrument -> assertThat(instrument.isEnabled()).isFalse());
assertThat(meter.histogramBuilder("test")).isInstanceOf(ExtendedDoubleHistogramBuilder.class);
assertThat(meter.histogramBuilder("test").build())
.isInstanceOfSatisfying(
ExtendedDoubleHistogram.class,
instrument -> assertThat(instrument.isEnabled()).isFalse());
Assertions.assertThat(meter.histogramBuilder("test").ofLongs().build())
.isInstanceOf(ExtendedLongHistogram.class);
Assertions.assertThat(meter.histogramBuilder("test"))
.isInstanceOf(ExtendedDoubleHistogramBuilder.class);
Assertions.assertThat(meter.histogramBuilder("test").build())
.isInstanceOf(ExtendedDoubleHistogram.class);
assertThat(meter.counterBuilder("test")).isInstanceOf(ExtendedLongCounterBuilder.class);
assertThat(meter.counterBuilder("test").build())
.isInstanceOfSatisfying(
ExtendedLongCounter.class, instrument -> assertThat(instrument.isEnabled()).isFalse());
assertThat(meter.counterBuilder("test").ofDoubles())
Assertions.assertThat(meter.counterBuilder("test"))
.isInstanceOf(ExtendedLongCounterBuilder.class);
Assertions.assertThat(meter.counterBuilder("test").build())
.isInstanceOf(ExtendedLongCounter.class);
Assertions.assertThat(meter.counterBuilder("test").ofDoubles())
.isInstanceOf(ExtendedDoubleCounterBuilder.class);
assertThat(meter.counterBuilder("test").ofDoubles().build())
.isInstanceOfSatisfying(
ExtendedDoubleCounter.class,
instrument -> assertThat(instrument.isEnabled()).isFalse());
Assertions.assertThat(meter.counterBuilder("test").ofDoubles().build())
.isInstanceOf(ExtendedDoubleCounter.class);
assertThat(meter.upDownCounterBuilder("test"))
Assertions.assertThat(meter.upDownCounterBuilder("test"))
.isInstanceOf(ExtendedLongUpDownCounterBuilder.class);
assertThat(meter.upDownCounterBuilder("test").build())
.isInstanceOfSatisfying(
ExtendedLongUpDownCounter.class,
instrument -> assertThat(instrument.isEnabled()).isFalse());
assertThat(meter.upDownCounterBuilder("test").ofDoubles())
Assertions.assertThat(meter.upDownCounterBuilder("test").build())
.isInstanceOf(ExtendedLongUpDownCounter.class);
Assertions.assertThat(meter.upDownCounterBuilder("test").ofDoubles())
.isInstanceOf(ExtendedDoubleUpDownCounterBuilder.class);
assertThat(meter.upDownCounterBuilder("test").ofDoubles().build())
.isInstanceOfSatisfying(
ExtendedDoubleUpDownCounter.class,
instrument -> assertThat(instrument.isEnabled()).isFalse());
Assertions.assertThat(meter.upDownCounterBuilder("test").ofDoubles().build())
.isInstanceOf(ExtendedDoubleUpDownCounter.class);
}
}

View File

@ -6,8 +6,6 @@
package io.opentelemetry.api.incubator.trace;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.testing.internal.AbstractDefaultTracerTest;
@ -29,20 +27,17 @@ class ExtendedDefaultTracerTest extends AbstractDefaultTracerTest {
}
@Test
void incubatingApiIsLoaded() {
public void incubatingApiIsLoaded() {
Tracer tracer = TracerProvider.noop().get("test");
assertThat(tracer).isSameAs(OpenTelemetry.noop().getTracer("test"));
assertThat(tracer)
.isInstanceOfSatisfying(
ExtendedTracer.class,
extendedTracer -> assertThat(extendedTracer.isEnabled()).isFalse());
assertThat(tracer).isInstanceOf(ExtendedTracer.class);
assertThat(tracer.spanBuilder("test")).isInstanceOf(ExtendedSpanBuilder.class);
}
@SuppressWarnings("unchecked")
@Test
void incubatingApi() {
public void incubatingApi() {
ExtendedSpanBuilder spanBuilder =
(ExtendedSpanBuilder) ExtendedDefaultTracer.getNoop().spanBuilder("test");
assertThat(spanBuilder.setParentFrom(null, null)).isSameAs(spanBuilder);
@ -50,21 +45,21 @@ class ExtendedDefaultTracerTest extends AbstractDefaultTracerTest {
SpanRunnable<RuntimeException> spanRunnable = Mockito.mock(SpanRunnable.class);
spanBuilder.startAndRun(spanRunnable);
verify(spanRunnable).runInSpan();
reset(spanRunnable);
Mockito.verify(spanRunnable).runInSpan();
Mockito.reset(spanRunnable);
spanBuilder.startAndRun(spanRunnable, null);
verify(spanRunnable).runInSpan();
reset(spanRunnable);
Mockito.verify(spanRunnable).runInSpan();
Mockito.reset(spanRunnable);
SpanCallable<String, RuntimeException> spanCallable = Mockito.mock(SpanCallable.class);
spanBuilder.startAndCall(spanCallable);
verify(spanCallable).callInSpan();
reset(spanCallable);
Mockito.verify(spanCallable).callInSpan();
Mockito.reset(spanCallable);
spanBuilder.startAndCall(spanCallable, null);
verify(spanCallable).callInSpan();
reset(spanCallable);
Mockito.verify(spanCallable).callInSpan();
Mockito.reset(spanCallable);
}
}

View File

@ -1,259 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.api.incubator;
import static org.assertj.core.api.Assertions.assertThat;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableMap;
import io.opentelemetry.api.incubator.config.ConfigProvider;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.api.incubator.config.InstrumentationConfigUtil;
import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfiguration;
import io.opentelemetry.sdk.extension.incubator.fileconfig.SdkConfigProvider;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalLanguageSpecificInstrumentationModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.InstrumentationModel;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel;
import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.junit.jupiter.api.Test;
class InstrumentationConfigUtilTest {
private static final ObjectMapper MAPPER = new ObjectMapper();
@Test
void toMap_RoundTrip() throws JsonProcessingException {
Map<String, Object> map = new HashMap<>();
map.put("string", "val");
map.put("boolean", true);
map.put("long", 1L);
map.put("double", 1.1);
map.put("null", null);
map.put("stringList", Arrays.asList("val1", "val2"));
map.put("boolList", Arrays.asList(true, false));
map.put("longList", Arrays.asList(1L, 2L));
map.put("doubleList", Arrays.asList(1.1d, 2.2d));
map.put(
"structuredList", Collections.singletonList(Collections.singletonMap("childKey", "val")));
map.put("emptyList", Collections.emptyList());
map.put("structured", Collections.singletonMap("childKey", "val"));
map.put("emptyStructured", Collections.emptyMap());
String mapJson = MAPPER.writeValueAsString(map);
DeclarativeConfigProperties properties =
DeclarativeConfiguration.toConfigProperties(
new ByteArrayInputStream(mapJson.getBytes(StandardCharsets.UTF_8)));
assertThat(DeclarativeConfigProperties.toMap(properties)).isEqualTo(map);
}
@Test
void getInstrumentationConfigModel_UnsetConfig() {
ConfigProvider configProvider = () -> null;
assertThat(
InstrumentationConfigUtil.getInstrumentationConfigModel(
configProvider, "my_instrumentation_library", MAPPER, Model.class))
.isEqualTo(null);
}
@Test
void getInstrumentationConfigModel_EmptyConfig() {
ConfigProvider configProvider =
withInstrumentationConfig("my_instrumentation_library", Collections.emptyMap());
assertThat(
InstrumentationConfigUtil.getInstrumentationConfigModel(
configProvider, "my_instrumentation_library", MAPPER, Model.class))
.isEqualTo(new Model());
}
@Test
void getInstrumentationConfigModel_KitchenSink() {
ConfigProvider configProvider =
withInstrumentationConfig(
"my_instrumentation_library",
ImmutableMap.<String, Object>builder()
.put("string_property", "value")
.put("boolean_property", true)
.put("long_property", 1L)
.put("double_property", 1.1d)
.put("string_list_property", Arrays.asList("val1", "val2"))
.put("boolean_list_property", Arrays.asList(true, false))
.put("long_list_property", Arrays.asList(1L, 2L))
.put("double_list_property", Arrays.asList(1.1d, 2.2d))
.put("map_property", Collections.singletonMap("childKey", "val"))
.put(
"structured_list_property",
Collections.singletonList(
ImmutableMap.of("key", "the_key", "value", "the_value")))
.build());
Model expected = new Model();
expected.stringProperty = "value";
expected.booleanProperty = true;
expected.longProperty = 1L;
expected.doubleProperty = 1.1d;
expected.stringListProperty = Arrays.asList("val1", "val2");
expected.booleanListProperty = Arrays.asList(true, false);
expected.longListProperty = Arrays.asList(1L, 2L);
expected.doubleListProperty = Arrays.asList(1.1d, 2.2d);
expected.mapProperty = Collections.singletonMap("childKey", "val");
ListEntryModel listEntryModel = new ListEntryModel();
listEntryModel.key = "the_key";
listEntryModel.value = "the_value";
expected.structuredListProperty = Collections.singletonList(listEntryModel);
assertThat(
InstrumentationConfigUtil.getInstrumentationConfigModel(
configProvider, "my_instrumentation_library", MAPPER, Model.class))
.isEqualTo(expected);
}
private static ConfigProvider withInstrumentationConfig(
String instrumentationName, Map<String, Object> instrumentationConfig) {
ExperimentalLanguageSpecificInstrumentationModel javaConfig =
new ExperimentalLanguageSpecificInstrumentationModel();
javaConfig.setAdditionalProperty(instrumentationName, instrumentationConfig);
return SdkConfigProvider.create(
new OpenTelemetryConfigurationModel()
.withInstrumentationDevelopment(new InstrumentationModel().withJava(javaConfig)));
}
private static class Model {
@JsonProperty("string_property")
private String stringProperty;
@JsonProperty("boolean_property")
private Boolean booleanProperty;
@JsonProperty("long_property")
private Long longProperty;
@JsonProperty("double_property")
private Double doubleProperty;
@JsonProperty("string_list_property")
private List<String> stringListProperty;
@JsonProperty("boolean_list_property")
private List<Boolean> booleanListProperty;
@JsonProperty("long_list_property")
private List<Long> longListProperty;
@JsonProperty("double_list_property")
private List<Double> doubleListProperty;
;
@JsonProperty("map_property")
private Map<String, Object> mapProperty;
@JsonProperty("structured_list_property")
private List<ListEntryModel> structuredListProperty;
@Override
public boolean equals(Object o) {
if (!(o instanceof Model)) {
return false;
}
Model model = (Model) o;
return Objects.equals(stringProperty, model.stringProperty)
&& Objects.equals(booleanProperty, model.booleanProperty)
&& Objects.equals(longProperty, model.longProperty)
&& Objects.equals(doubleProperty, model.doubleProperty)
&& Objects.equals(stringListProperty, model.stringListProperty)
&& Objects.equals(booleanListProperty, model.booleanListProperty)
&& Objects.equals(longListProperty, model.longListProperty)
&& Objects.equals(doubleListProperty, model.doubleListProperty)
&& Objects.equals(mapProperty, model.mapProperty)
&& Objects.equals(structuredListProperty, model.structuredListProperty);
}
@Override
public int hashCode() {
return Objects.hash(
stringProperty,
booleanProperty,
longProperty,
doubleProperty,
stringListProperty,
booleanListProperty,
longListProperty,
doubleListProperty,
mapProperty,
structuredListProperty);
}
@Override
public String toString() {
return "Model{"
+ "stringProperty='"
+ stringProperty
+ '\''
+ ", booleanProperty='"
+ booleanProperty
+ '\''
+ ", longProperty='"
+ longProperty
+ '\''
+ ", doubleProperty='"
+ doubleProperty
+ '\''
+ ", stringListProperty="
+ stringListProperty
+ ", booleanListProperty="
+ booleanListProperty
+ ", longListProperty="
+ longListProperty
+ ", doubleListProperty="
+ doubleListProperty
+ ", mapProperty="
+ mapProperty
+ ", structuredListProperty="
+ structuredListProperty
+ '}';
}
}
private static final class ListEntryModel {
@JsonProperty("key")
private String key;
@JsonProperty("value")
private String value;
@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) {
return false;
}
ListEntryModel that = (ListEntryModel) o;
return Objects.equals(key, that.key) && Objects.equals(value, that.value);
}
@Override
public int hashCode() {
return Objects.hash(key, value);
}
@Override
public String toString() {
return "ListEntryModel{" + "key='" + key + '\'' + ", value='" + value + '\'' + '}';
}
}
}

View File

@ -51,7 +51,8 @@ public abstract class AbstractDefaultLoggerTest {
() ->
getLogger()
.logRecordBuilder()
.setEventName("event name")
// TODO (trask) once event name stabilizes
// .setEventName("event name")
.setTimestamp(100, TimeUnit.SECONDS)
.setTimestamp(Instant.now())
.setObservedTimestamp(100, TimeUnit.SECONDS)

View File

@ -25,7 +25,7 @@ import io.opentelemetry.internal.testing.slf4j.SuppressLogger;
import org.junit.jupiter.api.Test;
/** Unit tests for No-op {@link Meter}. */
@SuppressLogger
@SuppressLogger()
public abstract class AbstractDefaultMeterTest {
private final Meter meter = getMeter();

View File

@ -12,10 +12,7 @@ nexusPublishing {
packageGroup.set("io.opentelemetry")
repositories {
// see https://central.sonatype.org/publish/publish-portal-ossrh-staging-api/#configuration
sonatype {
nexusUrl.set(uri("https://ossrh-staging-api.central.sonatype.com/service/local/"))
snapshotRepositoryUrl.set(uri("https://central.sonatype.com/repository/maven-snapshots/"))
username.set(System.getenv("SONATYPE_USER"))
password.set(System.getenv("SONATYPE_KEY"))
}

View File

@ -2,7 +2,7 @@ plugins {
`kotlin-dsl`
// When updating, update below in dependencies too
id("com.diffplug.spotless") version "7.2.1"
id("com.diffplug.spotless") version "7.0.2"
}
if (!hasLauncherForJavaVersion(17)) {
@ -50,23 +50,24 @@ repositories {
}
dependencies {
implementation(enforcedPlatform("com.squareup.wire:wire-bom:5.3.5"))
implementation(enforcedPlatform("com.squareup.wire:wire-bom:5.2.1"))
implementation("com.google.auto.value:auto-value-annotations:1.11.0")
// When updating, update above in plugins too
implementation("com.diffplug.spotless:spotless-plugin-gradle:7.2.1")
implementation("com.gradle.develocity:com.gradle.develocity.gradle.plugin:4.1")
implementation("com.diffplug.spotless:spotless-plugin-gradle:7.0.2")
// Needed for japicmp but not automatically brought in for some reason.
implementation("com.google.guava:guava:33.4.0-jre")
implementation("com.squareup:javapoet:1.13.0")
implementation("com.squareup.wire:wire-compiler")
implementation("com.squareup.wire:wire-gradle-plugin")
implementation("gradle.plugin.com.google.protobuf:protobuf-gradle-plugin:0.8.18")
implementation("gradle.plugin.io.morethan.jmhreport:gradle-jmh-report:0.9.6")
implementation("me.champeau.gradle:japicmp-gradle-plugin:0.4.6")
implementation("me.champeau.gradle:japicmp-gradle-plugin:0.4.5")
implementation("me.champeau.jmh:jmh-gradle-plugin:0.7.3")
implementation("net.ltgt.gradle:gradle-errorprone-plugin:4.3.0")
implementation("net.ltgt.gradle:gradle-errorprone-plugin:4.1.0")
implementation("net.ltgt.gradle:gradle-nullaway-plugin:2.2.0")
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:2.2.0")
implementation("org.owasp:dependency-check-gradle:12.1.3")
implementation("ru.vyarus:gradle-animalsniffer-plugin:2.0.1")
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:2.1.10")
implementation("org.owasp:dependency-check-gradle:12.0.2")
implementation("ru.vyarus:gradle-animalsniffer-plugin:2.0.0")
}
// We can't apply conventions to this build so include important ones such as the Java compilation

View File

@ -50,6 +50,7 @@ tasks {
disable("UnnecessarilyFullyQualified")
// We use animal sniffer
disable("Java7ApiChecker")
disable("Java8ApiChecker")
disable("AndroidJdkLibsChecker")
@ -86,10 +87,6 @@ tasks {
// cognitive load is dubious.
disable("YodaCondition")
// We annotate packages with @ParametersAreNonnullByDefault from com.google.code.findbugs:jsr305.
// @NullMarked is the equivalent from jspecify.
disable("AddNullMarkedToPackageInfo")
if ((name.contains("Jmh") || name.contains("Test") || project.name.contains("testing-internal")) && !project.name.equals("custom-checks")) {
// Allow underscore in test-type method names
disable("MemberName")

View File

@ -5,7 +5,7 @@ plugins {
}
jacoco {
toolVersion = "0.8.13"
toolVersion = "0.8.12"
}
// https://docs.gradle.org/current/samples/sample_jvm_multi_project_with_code_coverage.html

View File

@ -142,7 +142,6 @@ if (!project.hasProperty("otel.release") && !project.name.startsWith("bom")) {
// Temporarily suppress warnings from public generated classes from :sdk-extensions:jaeger-remote-sampler
"io.opentelemetry.sdk.extension.trace.jaeger.proto.api_v2"
)
annotationExcludes.add("@kotlin.Metadata")
val baseVersionString = if (apiBaseVersion == null) "latest" else baselineVersion
txtOutputFile.set(
apiNewVersion?.let { file("$rootDir/docs/apidiffs/${apiNewVersion}_vs_$baselineVersion/${base.archivesName.get()}.txt") }

View File

@ -42,7 +42,7 @@ java {
checkstyle {
configDirectory.set(file("$rootDir/buildscripts/"))
toolVersion = "10.26.1"
toolVersion = "10.21.2"
isIgnoreFailures = false
configProperties["rootDir"] = rootDir
}
@ -66,7 +66,6 @@ dependencyCheck {
"jmhRuntimeOnly")
failBuildOnCVSS = 7.0f // fail on high or critical CVE
analyzers.assemblyEnabled = false // not sure why its trying to analyze .NET assemblies
nvd.apiKey = System.getenv("NVD_API_KEY")
}
val testJavaVersion = gradle.startParameter.projectProperties.get("testJavaVersion")?.let(JavaVersion::toVersion)
@ -114,14 +113,6 @@ tasks {
)
}
val defaultMaxRetries = if (System.getenv().containsKey("CI")) 2 else 0
val maxTestRetries = gradle.startParameter.projectProperties["maxTestRetries"]?.toInt() ?: defaultMaxRetries
develocity.testRetry {
// You can see tests that were retried by this mechanism in the collected test reports and build scans.
maxRetries.set(maxTestRetries);
}
testLogging {
exceptionFormat = TestExceptionFormat.FULL
showExceptions = true

View File

@ -1,12 +0,0 @@
plugins {
id("otel.java-conventions")
id("otel.publish-conventions")
id("otel.animalsniffer-conventions")
}
description = "OpenTelemetry API Common"
otelJava.moduleName.set("io.opentelemetry.common")
dependencies {
}

View File

@ -1,28 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.common;
import java.util.ServiceLoader;
/** A loader for components that are discovered via SPI. */
public interface ComponentLoader {
/**
* Load implementations of an SPI.
*
* @param spiClass the SPI class
* @param <T> the SPI type
* @return iterable of SPI implementations
*/
<T> Iterable<T> load(Class<T> spiClass);
/**
* Create an instance for the {@code classLoader} using {@link ServiceLoader#load(Class,
* ClassLoader)}.
*/
static ComponentLoader forClassLoader(ClassLoader classLoader) {
return new ServiceLoaderComponentLoader(classLoader);
}
}

View File

@ -1,27 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.common;
import java.util.ServiceLoader;
class ServiceLoaderComponentLoader implements ComponentLoader {
private final ClassLoader classLoader;
ServiceLoaderComponentLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
@Override
public <T> Iterable<T> load(Class<T> spiClass) {
return ServiceLoader.load(spiClass, classLoader);
}
@Override
public String toString() {
return "ServiceLoaderComponentLoader{classLoader=" + classLoader + "}";
}
}

View File

@ -10,7 +10,6 @@ description = "OpenTelemetry Context (Incubator)"
otelJava.moduleName.set("io.opentelemetry.context")
dependencies {
api(project(":common"))
// MustBeClosed
compileOnly("com.google.errorprone:error_prone_annotations")

View File

@ -268,9 +268,6 @@ public interface Context {
* making this the {@linkplain Context#current() current context} before each execution.
*/
default ExecutorService wrap(ExecutorService executor) {
if (executor instanceof ContextExecutorService) {
return executor;
}
return new ContextExecutorService(this, executor);
}
@ -280,9 +277,6 @@ public interface Context {
* execution.
*/
default ScheduledExecutorService wrap(ScheduledExecutorService executor) {
if (executor instanceof ContextScheduledExecutorService) {
return executor;
}
return new ContextScheduledExecutorService(this, executor);
}

View File

@ -16,7 +16,7 @@ package io.opentelemetry.context;
* private static final ContextKey<MyState> KEY = ContextKey.named("MyState");
*
* public Context startWork() {
* return Context.with(KEY, new MyState());
* return Context.withValues(KEY, new MyState());
* }
*
* public void continueWork(Context context) {

View File

@ -37,9 +37,9 @@
package io.opentelemetry.context;
import io.opentelemetry.common.ComponentLoader;
import java.util.ArrayList;
import java.util.List;
import java.util.ServiceLoader;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.logging.Level;
@ -103,10 +103,8 @@ final class LazyStorage {
return ContextStorage.defaultStorage();
}
ComponentLoader componentLoader =
ComponentLoader.forClassLoader(LazyStorage.class.getClassLoader());
List<ContextStorageProvider> providers = new ArrayList<>();
for (ContextStorageProvider provider : componentLoader.load(ContextStorageProvider.class)) {
for (ContextStorageProvider provider : ServiceLoader.load(ContextStorageProvider.class)) {
if (provider
.getClass()
.getName()
@ -129,8 +127,7 @@ final class LazyStorage {
deferredStorageFailure.set(
new IllegalStateException(
"Found multiple ContextStorageProvider. Set the "
+ CONTEXT_STORAGE_PROVIDER_PROPERTY
+ " property to the fully "
+ "io.opentelemetry.context.ContextStorageProvider property to the fully "
+ "qualified class name of the provider to use. Falling back to default "
+ "ContextStorage. Found providers: "
+ providers));
@ -145,8 +142,7 @@ final class LazyStorage {
deferredStorageFailure.set(
new IllegalStateException(
CONTEXT_STORAGE_PROVIDER_PROPERTY
+ " property set but no matching class "
"io.opentelemetry.context.ContextStorageProvider property set but no matching class "
+ "could be found, requested: "
+ providerClassName
+ " but found providers: "

View File

@ -5,8 +5,6 @@
package io.opentelemetry.context.propagation;
import java.util.Collections;
import java.util.Iterator;
import javax.annotation.Nullable;
/**
@ -35,24 +33,4 @@ public interface TextMapGetter<C> {
*/
@Nullable
String get(@Nullable C carrier, String key);
/**
* If implemented, returns all values for a given {@code key} in order, or returns an empty list.
*
* <p>The default method returns the first value of the given propagation {@code key} as a
* singleton list, or returns an empty list.
*
* @param carrier carrier of propagation fields, such as an http request.
* @param key the key of the field.
* @return all values for a given {@code key} in order, or returns an empty list. Default method
* wraps {@code get()} as an {@link Iterator}.
* @since 1.50.0
*/
default Iterator<String> getAll(@Nullable C carrier, String key) {
String first = get(carrier, key);
if (first == null) {
return Collections.emptyIterator();
}
return Collections.singleton(first).iterator();
}
}

View File

@ -6,16 +6,39 @@
package io.opentelemetry.context.propagation.internal;
import io.opentelemetry.context.propagation.TextMapGetter;
import java.util.Collections;
import java.util.Iterator;
import javax.annotation.Nullable;
/**
* Extended {@link TextMapGetter} with experimental APIs.
* Extends {@link TextMapGetter} to return possibly multiple values for a given key.
*
* <p>This class is internal and experimental. Its APIs are unstable and can change at any time. Its
* APIs (or a version of them) may be promoted to the public stable API in the future, but no
* guarantees are made.
*
* @param <C> carrier of propagation fields, such as an http request.
*/
public interface ExtendedTextMapGetter<C> extends TextMapGetter<C> {
// keep this class even if it is empty, since experimental methods may be added in the future.
/**
* If implemented, returns all values for a given {@code key} in order, or returns an empty list.
*
* <p>The default method returns the first value of the given propagation {@code key} as a
* singleton list, or returns an empty list.
*
* <p>This class is internal and is hence not for public use. Its APIs are unstable and can change
* at any time.
*
* @param carrier carrier of propagation fields, such as an http request.
* @param key the key of the field.
* @return all values for a given {@code key} in order, or returns an empty list. Default method
* wraps {@code get()} as an {@link Iterator}.
*/
default Iterator<String> getAll(@Nullable C carrier, String key) {
String first = get(carrier, key);
if (first == null) {
return Collections.emptyIterator();
}
return Collections.singleton(first).iterator();
}
}

View File

@ -7,7 +7,6 @@ package io.opentelemetry.context;
import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.doNothing;
@ -109,12 +108,6 @@ class ContextTest {
assertThat(Context.current().get(ANIMAL)).isNull();
}
@Test
void keyEqualityIsInstanceCheck() {
Context context = Context.current().with(ContextKey.named("animal"), "cat");
assertNull(context.get(ContextKey.named("animal"))); // yup
}
@Test
void newThreadStartsWithRoot() throws Exception {
Context context = Context.current().with(ANIMAL, "cat");
@ -368,24 +361,6 @@ class ContextTest {
}
}
@Test
void wrapExecutorService() {
// given
ExecutorService executorService = Executors.newSingleThreadExecutor();
// when
ExecutorService firstWrap = CAT.wrap(executorService);
ExecutorService secondWrap = CAT.wrap(firstWrap);
// then
assertThat(firstWrap).isInstanceOf(ContextExecutorService.class);
assertThat(((ContextExecutorService) firstWrap).context()).isEqualTo(CAT);
assertThat(((ContextExecutorService) firstWrap).delegate()).isEqualTo(executorService);
assertThat(secondWrap).isInstanceOf(ContextExecutorService.class);
assertThat(((ContextExecutorService) secondWrap).context()).isEqualTo(CAT);
assertThat(((ContextExecutorService) secondWrap).delegate()).isEqualTo(executorService);
}
@Nested
@TestInstance(Lifecycle.PER_CLASS)
class WrapExecutorService {
@ -529,25 +504,6 @@ class ContextTest {
}
}
@Test
void wrapScheduledExecutorService() {
// given
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
// when
ScheduledExecutorService firstWrap = CAT.wrap(executorService);
ScheduledExecutorService secondWrap = CAT.wrap(firstWrap);
// then
assertThat(firstWrap).isInstanceOf(ContextScheduledExecutorService.class);
assertThat(((ContextScheduledExecutorService) firstWrap).context()).isEqualTo(CAT);
assertThat(((ContextScheduledExecutorService) firstWrap).delegate()).isEqualTo(executorService);
assertThat(secondWrap).isInstanceOf(ContextScheduledExecutorService.class);
assertThat(((ContextScheduledExecutorService) secondWrap).context()).isEqualTo(CAT);
assertThat(((ContextScheduledExecutorService) secondWrap).delegate())
.isEqualTo(executorService);
}
@Nested
@TestInstance(Lifecycle.PER_CLASS)
class WrapScheduledExecutorService {

View File

@ -3,12 +3,11 @@
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.context.propagation;
package io.opentelemetry.context.propagation.internal;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import com.google.common.collect.ImmutableList;
import io.opentelemetry.context.propagation.internal.ExtendedTextMapGetter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
@ -16,9 +15,9 @@ import java.util.List;
import javax.annotation.Nullable;
import org.junit.jupiter.api.Test;
class TextMapGetterTest {
class ExtendedTextMapGetterTest {
final TextMapGetter<Void> nullGet =
final ExtendedTextMapGetter<Void> nullGet =
new ExtendedTextMapGetter<Void>() {
@Override
public Iterable<String> keys(Void carrier) {
@ -32,7 +31,7 @@ class TextMapGetterTest {
}
};
final TextMapGetter<Void> nonNullGet =
final ExtendedTextMapGetter<Void> nonNullGet =
new ExtendedTextMapGetter<Void>() {
@Override
public Iterable<String> keys(Void carrier) {

View File

@ -3,7 +3,7 @@ plugins {
}
dependencies {
compileOnly("com.google.errorprone:error_prone_core")
implementation("com.google.errorprone:error_prone_core")
testImplementation("com.google.errorprone:error_prone_test_helpers")
}
@ -80,8 +80,3 @@ configurations {
}
}
}
// Skip OWASP dependencyCheck task on test module
dependencyCheck {
skip = true
}

View File

@ -11,48 +11,14 @@ import org.junit.jupiter.api.Test;
class OtelInternalJavadocTest {
@Test
void positiveCases() {
CompilationTestHelper.newInstance(OtelInternalJavadoc.class, OtelInternalJavadocTest.class)
.addSourceLines(
"internal/InternalJavadocPositiveCases.java",
"/*",
" * Copyright The OpenTelemetry Authors",
" * SPDX-License-Identifier: Apache-2.0",
" */",
"package io.opentelemetry.gradle.customchecks.internal;",
"// BUG: Diagnostic contains: doesn't end with any of the applicable javadoc disclaimers",
"public class InternalJavadocPositiveCases {",
" // BUG: Diagnostic contains: doesn't end with any of the applicable javadoc disclaimers",
" public static class One {}",
" /** Doesn't have the disclaimer. */",
" // BUG: Diagnostic contains: doesn't end with any of the applicable javadoc disclaimers",
" public static class Two {}",
"}")
.doTest();
void test() {
doTest("internal/InternalJavadocPositiveCases.java");
doTest("internal/InternalJavadocNegativeCases.java");
}
@Test
void negativeCases() {
private static void doTest(String path) {
CompilationTestHelper.newInstance(OtelInternalJavadoc.class, OtelInternalJavadocTest.class)
.addSourceLines(
"internal/InternalJavadocNegativeCases.java",
"/*",
" * Copyright The OpenTelemetry Authors",
" * SPDX-License-Identifier: Apache-2.0",
" */",
"package io.opentelemetry.gradle.customchecks.internal;",
"/**",
" * This class is internal and is hence not for public use. Its APIs are unstable and can change at",
" * any time.",
" */",
"public class InternalJavadocNegativeCases {",
" /**",
" * This class is internal and is hence not for public use. Its APIs are unstable and can change at",
" * any time.",
" */",
" public static class One {}",
" static class Two {}",
"}")
.addSourceFile(path)
.doTest();
}
}

View File

@ -0,0 +1,21 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.gradle.customchecks.internal;
/**
* This class is internal and is hence not for public use. Its APIs are unstable and can change at
* any time.
*/
public class InternalJavadocNegativeCases {
/**
* This class is internal and is hence not for public use. Its APIs are unstable and can change at
* any time.
*/
public static class One {}
static class Two {}
}

View File

@ -0,0 +1,17 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.gradle.customchecks.internal;
// BUG: Diagnostic contains: doesn't end with any of the applicable javadoc disclaimers
public class InternalJavadocPositiveCases {
// BUG: Diagnostic contains: doesn't end with any of the applicable javadoc disclaimers
public static class One {}
/** Doesn't have the disclaimer. */
// BUG: Diagnostic contains: doesn't end with any of the applicable javadoc disclaimers
public static class Two {}
}

View File

@ -7,48 +7,34 @@ data class DependencySet(val group: String, val version: String, val modules: Li
val dependencyVersions = hashMapOf<String, String>()
rootProject.extra["versions"] = dependencyVersions
val DEPENDENCY_BOMS = listOf(
"com.fasterxml.jackson:jackson-bom:2.18.2",
"com.google.guava:guava-bom:33.4.0-jre",
"com.google.protobuf:protobuf-bom:4.29.3",
"com.linecorp.armeria:armeria-bom:1.31.3",
"com.squareup.okhttp3:okhttp-bom:4.12.0",
"com.squareup.okio:okio-bom:3.10.2", // applies to transitive dependencies of okhttp
"io.grpc:grpc-bom:1.70.0",
"io.netty:netty-bom:4.1.117.Final",
"io.zipkin.brave:brave-bom:6.0.3",
"io.zipkin.reporter2:zipkin-reporter-bom:3.4.3",
"org.assertj:assertj-bom:3.27.3",
"org.junit:junit-bom:5.11.4",
"org.testcontainers:testcontainers-bom:1.20.4",
"org.snakeyaml:snakeyaml-engine:2.9"
)
val autoValueVersion = "1.11.0"
val errorProneVersion = "2.41.0"
val errorProneVersion = "2.36.0"
val jmhVersion = "1.37"
// Mockito 5.x.x requires Java 11 https://github.com/mockito/mockito/releases/tag/v5.0.0
val mockitoVersion = "4.11.0"
val slf4jVersion = "2.0.17"
val slf4jVersion = "2.0.16"
val opencensusVersion = "0.31.1"
val prometheusServerVersion = "1.3.10"
val armeriaVersion = "1.32.5"
val junitVersion = "5.13.4"
val okhttpVersion = "5.1.0"
val DEPENDENCY_BOMS = listOf(
// for some reason boms show up as runtime dependencies in license and vulnerability scans
// even if they are only used by test dependencies, so not using junit bom here
// (which is EPL licensed) or armeria bom (which is Apache licensed but is getting flagged
// by FOSSA for containing EPL-licensed)
"com.fasterxml.jackson:jackson-bom:2.19.2",
"com.google.guava:guava-bom:33.4.8-jre",
"com.google.protobuf:protobuf-bom:4.31.1",
"com.squareup.okhttp3:okhttp-bom:$okhttpVersion",
"com.squareup.okio:okio-bom:3.15.0", // applies to transitive dependencies of okhttp
"io.grpc:grpc-bom:1.74.0",
"io.netty:netty-bom:4.2.3.Final",
"io.zipkin.brave:brave-bom:6.3.0",
"io.zipkin.reporter2:zipkin-reporter-bom:3.5.1",
"org.assertj:assertj-bom:3.27.3",
"org.testcontainers:testcontainers-bom:1.21.3",
"org.snakeyaml:snakeyaml-engine:2.10"
)
val prometheusClientVersion = "0.16.0"
val prometheusServerVersion = "1.3.5"
val DEPENDENCIES = listOf(
"org.junit.jupiter:junit-jupiter-api:${junitVersion}",
"org.junit.jupiter:junit-jupiter-params:${junitVersion}",
"org.junit.jupiter:junit-jupiter-pioneer:${junitVersion}",
"com.linecorp.armeria:armeria:${armeriaVersion}",
"com.linecorp.armeria:armeria-grpc:${armeriaVersion}",
"com.linecorp.armeria:armeria-grpc-protocol:${armeriaVersion}",
"com.linecorp.armeria:armeria-junit5:${armeriaVersion}",
"com.google.auto.value:auto-value:${autoValueVersion}",
"com.google.auto.value:auto-value-annotations:${autoValueVersion}",
"com.google.errorprone:error_prone_annotations:${errorProneVersion}",
@ -66,36 +52,39 @@ val DEPENDENCIES = listOf(
"org.mockito:mockito-junit-jupiter:${mockitoVersion}",
"org.slf4j:slf4j-simple:${slf4jVersion}",
"org.slf4j:jul-to-slf4j:${slf4jVersion}",
"io.prometheus:prometheus-metrics-shaded-protobuf:1.3.1",
"io.prometheus:prometheus-metrics-exporter-httpserver:${prometheusServerVersion}",
"io.prometheus:prometheus-metrics-exposition-formats-no-protobuf:${prometheusServerVersion}",
"io.prometheus:prometheus-metrics-exposition-formats:${prometheusServerVersion}",
"io.prometheus:simpleclient:${prometheusClientVersion}",
"io.prometheus:simpleclient_common:${prometheusClientVersion}",
"io.prometheus:simpleclient_httpserver:${prometheusClientVersion}",
"javax.annotation:javax.annotation-api:1.3.2",
"com.github.stefanbirkner:system-rules:1.19.0",
"com.google.api.grpc:proto-google-common-protos:2.59.2",
"com.google.api.grpc:proto-google-common-protos:2.51.0",
"com.google.code.findbugs:jsr305:3.0.2",
"com.google.guava:guava-beta-checker:1.0",
"com.sun.net.httpserver:http:20070405",
"com.squareup.okhttp3:okhttp-jvm:$okhttpVersion",
"com.tngtech.archunit:archunit-junit5:1.4.1",
"com.uber.nullaway:nullaway:0.12.7",
"com.tngtech.archunit:archunit-junit5:1.3.0",
"com.uber.nullaway:nullaway:0.12.3",
"edu.berkeley.cs.jqf:jqf-fuzz:1.7", // jqf-fuzz version 1.8+ requires Java 11+
"eu.rekawek.toxiproxy:toxiproxy-java:2.1.7",
"io.github.netmikey.logunit:logunit-jul:2.0.0",
"io.jaegertracing:jaeger-client:1.8.1",
"io.opentelemetry.contrib:opentelemetry-aws-xray-propagator:1.48.0-alpha",
"io.opentelemetry.semconv:opentelemetry-semconv-incubating:1.34.0-alpha",
"io.opentelemetry.proto:opentelemetry-proto:1.7.0-alpha",
"io.opentelemetry.contrib:opentelemetry-aws-xray-propagator:1.39.0-alpha",
"io.opentelemetry.semconv:opentelemetry-semconv-incubating:1.30.0-alpha-rc.1",
"io.opentelemetry.proto:opentelemetry-proto:1.5.0-alpha",
"io.opentracing:opentracing-api:0.33.0",
"io.opentracing:opentracing-noop:0.33.0",
"junit:junit:4.13.2",
"nl.jqno.equalsverifier:equalsverifier:3.19.4",
"org.awaitility:awaitility:4.3.0",
"nl.jqno.equalsverifier:equalsverifier:3.19",
"org.awaitility:awaitility:4.2.2",
"org.bouncycastle:bcpkix-jdk15on:1.70",
"org.codehaus.mojo:animal-sniffer-annotations:1.24",
"org.jctools:jctools-core:4.0.5",
"org.junit-pioneer:junit-pioneer:1.9.1",
"org.mock-server:mockserver-netty:5.15.0:shaded",
"org.skyscreamer:jsonassert:1.5.3",
"com.android.tools:desugar_jdk_libs:2.1.5",
"com.android.tools:desugar_jdk_libs:2.1.4",
)
javaPlatform {

Some files were not shown because too many files have changed in this diff Show More