diff --git a/benchmarks/build.gradle b/benchmarks/build.gradle new file mode 100644 index 00000000..2f878a0a --- /dev/null +++ b/benchmarks/build.gradle @@ -0,0 +1,21 @@ +dependencies { + jmh project(':micrometer-tracing-bridge-brave') + jmh project(':micrometer-tracing-bridge-otel') + jmh 'org.openjdk.jmh:jmh-core:latest.release' + jmh 'io.zipkin.brave:brave-tests' + + jmh 'ch.qos.logback:logback-classic' + + // Nebula doesn't like having jmhAnnotationProcessor without jmh so we just add it twice. + jmh 'org.openjdk.jmh:jmh-generator-annprocess:latest.release' + jmhAnnotationProcessor 'org.openjdk.jmh:jmh-generator-annprocess:latest.release' +} + +jmh { + jmhVersion = '1.36' + fork = 1 + warmupIterations = 1 + iterations = 1 + duplicateClassesStrategy = DuplicatesStrategy.EXCLUDE + zip64 = true +} diff --git a/benchmarks/gradle.lockfile b/benchmarks/gradle.lockfile new file mode 100644 index 00000000..ec183e15 --- /dev/null +++ b/benchmarks/gradle.lockfile @@ -0,0 +1,83 @@ +# This is a Gradle generated file for dependency locking. +# Manual edits can break the build and are not advised. +# This file is expected to be part of source control. +antlr:antlr:2.7.7=nohttp +aopalliance:aopalliance:1.0=jmh,jmhCompileClasspath,jmhRuntimeClasspath +ch.qos.logback:logback-classic:1.2.12=jmh,jmhCompileClasspath,jmhRuntimeClasspath +ch.qos.logback:logback-classic:1.2.3=checkstyle,nohttp,nohttp-cli +ch.qos.logback:logback-core:1.2.12=jmh,jmhCompileClasspath,jmhRuntimeClasspath +ch.qos.logback:logback-core:1.2.3=checkstyle,nohttp,nohttp-cli +com.google.code.findbugs:jsr305:3.0.2=checkstyle,compileClasspath,jmhRuntimeClasspath,nohttp,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +com.google.errorprone:error_prone_annotations:2.3.4=nohttp +com.google.errorprone:error_prone_annotations:2.7.1=checkstyle +com.google.guava:failureaccess:1.0.1=checkstyle,nohttp +com.google.guava:guava:29.0-jre=nohttp +com.google.guava:guava:31.0.1-jre=checkstyle +com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=checkstyle,nohttp +com.google.j2objc:j2objc-annotations:1.3=checkstyle,nohttp +com.puppycrawl.tools:checkstyle:8.33=nohttp +com.puppycrawl.tools:checkstyle:9.3=checkstyle +commons-beanutils:commons-beanutils:1.9.4=checkstyle,nohttp +commons-collections:commons-collections:3.2.2=checkstyle,nohttp +commons-logging:commons-logging:1.2=nohttp +info.picocli:picocli:3.9.5=nohttp-cli +info.picocli:picocli:4.3.1=nohttp +info.picocli:picocli:4.6.2=checkstyle +io.micrometer:context-propagation:1.0.3=jmh,jmhCompileClasspath,jmhRuntimeClasspath +io.micrometer:micrometer-bom:1.11.2-SNAPSHOT=jmh,jmhCompileClasspath,jmhRuntimeClasspath +io.micrometer:micrometer-commons:1.11.2-SNAPSHOT=jmh,jmhCompileClasspath,jmhRuntimeClasspath +io.micrometer:micrometer-observation:1.11.2-SNAPSHOT=jmh,jmhCompileClasspath,jmhRuntimeClasspath +io.opentelemetry.instrumentation:opentelemetry-instrumentation-api-semconv:1.24.0-alpha=jmh,jmhCompileClasspath,jmhRuntimeClasspath +io.opentelemetry.instrumentation:opentelemetry-instrumentation-api:1.24.0=jmh,jmhCompileClasspath,jmhRuntimeClasspath +io.opentelemetry:opentelemetry-api-events:1.25.0-alpha=jmh,jmhRuntimeClasspath +io.opentelemetry:opentelemetry-api-logs:1.25.0-alpha=jmh,jmhRuntimeClasspath +io.opentelemetry:opentelemetry-api:1.25.0=jmh,jmhCompileClasspath,jmhRuntimeClasspath +io.opentelemetry:opentelemetry-bom-alpha:1.25.0-alpha=jmh,jmhCompileClasspath,jmhRuntimeClasspath +io.opentelemetry:opentelemetry-bom:1.25.0=jmh,jmhCompileClasspath,jmhRuntimeClasspath +io.opentelemetry:opentelemetry-context:1.25.0=jmh,jmhCompileClasspath,jmhRuntimeClasspath +io.opentelemetry:opentelemetry-extension-trace-propagators:1.25.0=jmh,jmhCompileClasspath,jmhRuntimeClasspath +io.opentelemetry:opentelemetry-sdk-common:1.25.0=jmh,jmhCompileClasspath,jmhRuntimeClasspath +io.opentelemetry:opentelemetry-sdk-logs:1.25.0-alpha=jmh,jmhRuntimeClasspath +io.opentelemetry:opentelemetry-sdk-metrics:1.25.0=jmh,jmhCompileClasspath,jmhRuntimeClasspath +io.opentelemetry:opentelemetry-sdk-trace:1.25.0=jmh,jmhCompileClasspath,jmhRuntimeClasspath +io.opentelemetry:opentelemetry-sdk:1.25.0=jmh,jmhCompileClasspath,jmhRuntimeClasspath +io.opentelemetry:opentelemetry-semconv:1.25.0-alpha=jmh,jmhCompileClasspath,jmhRuntimeClasspath +io.projectreactor:reactor-bom:2022.0.8=jmh,jmhCompileClasspath,jmhRuntimeClasspath +io.spring.javaformat:spring-javaformat-checkstyle:0.0.39=checkstyle +io.spring.javaformat:spring-javaformat-config:0.0.39=checkstyle +io.spring.nohttp:nohttp-checkstyle:0.0.11=checkstyle,nohttp +io.spring.nohttp:nohttp-cli:0.0.11=nohttp-cli +io.spring.nohttp:nohttp:0.0.11=checkstyle,nohttp,nohttp-cli +io.zipkin.aws:brave-propagation-aws:0.23.4=jmh,jmhCompileClasspath,jmhRuntimeClasspath +io.zipkin.brave:brave-bom:5.14.1=jmh,jmhCompileClasspath,jmhRuntimeClasspath +io.zipkin.brave:brave-context-slf4j:5.14.1=jmh,jmhCompileClasspath,jmhRuntimeClasspath +io.zipkin.brave:brave-instrumentation-http:5.14.1=jmh,jmhCompileClasspath,jmhRuntimeClasspath +io.zipkin.brave:brave-tests:5.14.1=jmh,jmhCompileClasspath,jmhRuntimeClasspath +io.zipkin.brave:brave:5.14.1=jmh,jmhCompileClasspath,jmhRuntimeClasspath +io.zipkin.reporter2:zipkin-reporter-brave:2.16.3=jmh,jmhCompileClasspath,jmhRuntimeClasspath +io.zipkin.reporter2:zipkin-reporter:2.16.3=jmh,jmhCompileClasspath,jmhRuntimeClasspath +io.zipkin.zipkin2:zipkin:2.23.2=jmh,jmhCompileClasspath,jmhRuntimeClasspath +junit:junit:4.13.1=jmh,jmhCompileClasspath,jmhRuntimeClasspath +net.bytebuddy:byte-buddy:1.12.21=jmh,jmhCompileClasspath,jmhRuntimeClasspath +net.sf.jopt-simple:jopt-simple:5.0.4=jmh,jmhAnnotationProcessor,jmhCompileClasspath,jmhRuntimeClasspath +net.sf.saxon:Saxon-HE:10.6=checkstyle +net.sf.saxon:Saxon-HE:9.9.1-7=nohttp +org.antlr:antlr4-runtime:4.8-1=nohttp +org.antlr:antlr4-runtime:4.9.3=checkstyle +org.apache.commons:commons-math3:3.2=jmh,jmhAnnotationProcessor,jmhCompileClasspath,jmhRuntimeClasspath +org.assertj:assertj-core:3.24.2=jmh,jmhCompileClasspath,jmhRuntimeClasspath +org.checkerframework:checker-qual:2.11.1=nohttp +org.checkerframework:checker-qual:3.12.0=checkstyle +org.hamcrest:hamcrest-core:1.3=jmh,jmhCompileClasspath,jmhRuntimeClasspath +org.javassist:javassist:3.28.0-GA=checkstyle +org.junit:junit-bom:5.9.3=jmh,jmhCompileClasspath,jmhRuntimeClasspath +org.openjdk.jmh:jmh-core:1.36=jmh,jmhAnnotationProcessor,jmhCompileClasspath,jmhRuntimeClasspath +org.openjdk.jmh:jmh-generator-annprocess:1.36=jmh,jmhAnnotationProcessor,jmhCompileClasspath,jmhRuntimeClasspath +org.openjdk.jmh:jmh-generator-asm:1.36=jmh,jmhCompileClasspath,jmhRuntimeClasspath +org.openjdk.jmh:jmh-generator-bytecode:1.36=jmh,jmhCompileClasspath,jmhRuntimeClasspath +org.openjdk.jmh:jmh-generator-reflection:1.36=jmh,jmhCompileClasspath,jmhRuntimeClasspath +org.ow2.asm:asm:9.0=jmh,jmhCompileClasspath,jmhRuntimeClasspath +org.reflections:reflections:0.10.2=checkstyle +org.slf4j:slf4j-api:1.7.26=nohttp,nohttp-cli +org.slf4j:slf4j-api:1.7.36=jmh,jmhCompileClasspath,jmhRuntimeClasspath +empty=annotationProcessor,signatures,testAnnotationProcessor diff --git a/benchmarks/src/jmh/.gitignore b/benchmarks/src/jmh/.gitignore new file mode 100644 index 00000000..86d4c2dd --- /dev/null +++ b/benchmarks/src/jmh/.gitignore @@ -0,0 +1 @@ +generated diff --git a/benchmarks/src/jmh/java/io/micrometer/benchmark/tracer/BraveTracerBenchmark.java b/benchmarks/src/jmh/java/io/micrometer/benchmark/tracer/BraveTracerBenchmark.java new file mode 100644 index 00000000..35182636 --- /dev/null +++ b/benchmarks/src/jmh/java/io/micrometer/benchmark/tracer/BraveTracerBenchmark.java @@ -0,0 +1,154 @@ +/* + * Copyright 2017 VMware, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.micrometer.benchmark.tracer; + +import brave.Span; +import brave.Tracing; +import brave.handler.SpanHandler; +import brave.propagation.ThreadLocalCurrentTraceContext; +import brave.propagation.TraceContextOrSamplingFlags; +import brave.sampler.Sampler; +import io.micrometer.tracing.Tracer; +import io.micrometer.tracing.brave.bridge.BraveBaggageManager; +import io.micrometer.tracing.brave.bridge.BraveCurrentTraceContext; +import io.micrometer.tracing.brave.bridge.BraveTracer; +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.Blackhole; + +@BenchmarkMode(Mode.Throughput) +public class BraveTracerBenchmark implements MicrometerTracingBenchmarks { + + @State(Scope.Benchmark) + public static class MicrometerTracingState { + + @Param({ "5" }) + public int childSpanCount; + + ThreadLocalCurrentTraceContext braveCurrentTraceContext; + + BraveCurrentTraceContext bridgeContext; + + Tracing tracing; + + brave.Tracer braveTracer; + + Tracer tracer; + + @Setup + public void setup() { + this.braveCurrentTraceContext = ThreadLocalCurrentTraceContext.newBuilder().build(); + this.bridgeContext = new BraveCurrentTraceContext(this.braveCurrentTraceContext); + this.tracing = Tracing.newBuilder() + .currentTraceContext(this.braveCurrentTraceContext) + .sampler(Sampler.NEVER_SAMPLE) + .addSpanHandler(SpanHandler.NOOP) + .build(); + this.tracing.setNoop(true); + this.braveTracer = this.tracing.tracer(); + this.tracer = new BraveTracer(this.braveTracer, this.bridgeContext, new BraveBaggageManager()); + } + + @TearDown + public void close() { + this.tracing.close(); + } + + } + + @Benchmark + public void micrometerTracing(MicrometerTracingState state, Blackhole blackhole) { + micrometerTracing(state.tracer, state.childSpanCount, blackhole); + } + + @Benchmark + public io.micrometer.tracing.Span micrometerTracingNewSpan(MicrometerTracingState state) { + return micrometerTracingNewSpan(state.tracer); + } + + @Benchmark + public void micrometerTracingWithScope(MicrometerTracingState state, Blackhole blackhole) { + micrometerTracingWithScope(state.tracer, state.childSpanCount, blackhole); + } + + @State(Scope.Benchmark) + public static class BraveState { + + @Param({ "5" }) + public int childSpanCount; + + ThreadLocalCurrentTraceContext braveCurrentTraceContext; + + Tracing tracing; + + brave.Tracer tracer; + + @Setup + public void setup() { + this.braveCurrentTraceContext = ThreadLocalCurrentTraceContext.newBuilder().build(); + this.tracing = Tracing.newBuilder() + .currentTraceContext(this.braveCurrentTraceContext) + .sampler(Sampler.NEVER_SAMPLE) + .addSpanHandler(SpanHandler.NOOP) + .build(); + this.tracing.setNoop(true); + this.tracer = this.tracing.tracer(); + } + + @TearDown + public void close() { + this.tracing.close(); + } + + } + + @Benchmark + public void braveTracing(BraveState state, Blackhole blackhole) { + brave.Span parentSpan = state.tracer.nextSpan().name("parent-span").start(); + TraceContextOrSamplingFlags traceContext = TraceContextOrSamplingFlags.create(parentSpan.context()); + for (int i = 0; i < state.childSpanCount; i++) { + brave.Span span = state.tracer.nextSpan(traceContext).name("new-span" + i); + span.start().tag("key", "value").annotate("event").finish(); + blackhole.consume(span); + } + parentSpan.finish(); + blackhole.consume(parentSpan); + } + + @Benchmark + public Span braveTracingNewSpan(BraveState state, Blackhole blackhole) { + brave.Span span = state.tracer.nextSpan().name("child-span").start(); + span.finish(); + return span; + } + + @Benchmark + public void braveTracingWithScope(BraveState state, Blackhole blackhole) { + brave.Span parentSpan = state.tracer.nextSpan().name("parent-span").start(); + try (brave.Tracer.SpanInScope spanInScope = state.tracer.withSpanInScope(parentSpan)) { + for (int i = 0; i < state.childSpanCount; i++) { + brave.Span childSpan = state.tracer.nextSpan().name("new-span" + i); + try (brave.Tracer.SpanInScope spanInScope2 = state.tracer.withSpanInScope(childSpan.start())) { + childSpan.tag("key", "value").annotate("event"); + } + childSpan.finish(); + blackhole.consume(childSpan); + } + } + parentSpan.finish(); + blackhole.consume(parentSpan); + } + +} diff --git a/benchmarks/src/jmh/java/io/micrometer/benchmark/tracer/MicrometerTracingBenchmarks.java b/benchmarks/src/jmh/java/io/micrometer/benchmark/tracer/MicrometerTracingBenchmarks.java new file mode 100644 index 00000000..9e812731 --- /dev/null +++ b/benchmarks/src/jmh/java/io/micrometer/benchmark/tracer/MicrometerTracingBenchmarks.java @@ -0,0 +1,56 @@ +/* + * Copyright 2017 VMware, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.micrometer.benchmark.tracer; + +import io.micrometer.tracing.Span; +import io.micrometer.tracing.Tracer; +import org.openjdk.jmh.infra.Blackhole; + +interface MicrometerTracingBenchmarks { + + default void micrometerTracing(Tracer tracer, int childSpanCount, Blackhole blackhole) { + Span parentSpan = tracer.nextSpan().name("parent-span").start(); + for (int i = 0; i < childSpanCount; i++) { + Span span = tracer.nextSpan(parentSpan).name("new-span" + i); + span.start().tag("key", "value").event("event").end(); + blackhole.consume(span); + } + parentSpan.end(); + blackhole.consume(parentSpan); + } + + default Span micrometerTracingNewSpan(Tracer tracer) { + Span span = tracer.nextSpan().name("child-span").start(); + span.end(); + return span; + } + + default void micrometerTracingWithScope(Tracer tracer, int childSpanCount, Blackhole blackhole) { + Span parentSpan = tracer.nextSpan().name("parent-span").start(); + try (Tracer.SpanInScope ws = tracer.withSpan(parentSpan)) { + for (int i = 0; i < childSpanCount; i++) { + Span childSpan = tracer.nextSpan().name("new-span" + i).start(); + try (Tracer.SpanInScope ws2 = tracer.withSpan(childSpan)) { + childSpan.tag("key", "value").event("event"); + } + childSpan.end(); + } + } + parentSpan.end(); + blackhole.consume(parentSpan); + } + +} diff --git a/benchmarks/src/jmh/java/io/micrometer/benchmark/tracer/OtelTracerBenchmark.java b/benchmarks/src/jmh/java/io/micrometer/benchmark/tracer/OtelTracerBenchmark.java new file mode 100644 index 00000000..5556bed0 --- /dev/null +++ b/benchmarks/src/jmh/java/io/micrometer/benchmark/tracer/OtelTracerBenchmark.java @@ -0,0 +1,163 @@ +/* + * Copyright 2017 VMware, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.micrometer.benchmark.tracer; + +import io.micrometer.tracing.Span; +import io.micrometer.tracing.otel.bridge.OtelBaggageManager; +import io.micrometer.tracing.otel.bridge.OtelCurrentTraceContext; +import io.micrometer.tracing.otel.bridge.OtelTracer; +import io.opentelemetry.context.Context; +import io.opentelemetry.sdk.OpenTelemetrySdk; +import io.opentelemetry.sdk.trace.SdkTracerProvider; +import io.opentelemetry.sdk.trace.samplers.Sampler; +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.Blackhole; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +import java.util.Collections; + +@BenchmarkMode(Mode.Throughput) +public class OtelTracerBenchmark implements MicrometerTracingBenchmarks { + + public static void main(String[] args) throws RunnerException { + Options opt = new OptionsBuilder().include(OtelTracerBenchmark.class.getSimpleName()) + .warmupIterations(5) + .measurementIterations(10) + .mode(Mode.SampleTime) + .forks(1) + .build(); + + new Runner(opt).run(); + } + + @State(Scope.Benchmark) + public static class MicrometerTracingState { + + @Param({ "5" }) + public int childSpanCount; + + SdkTracerProvider sdkTracerProvider; + + OpenTelemetrySdk openTelemetrySdk; + + io.opentelemetry.api.trace.Tracer otelTracer; + + OtelCurrentTraceContext otelCurrentTraceContext; + + OtelTracer tracer; + + Span createdSpan; + + Span startedSpan; + + @Setup + public void setup() { + this.sdkTracerProvider = SdkTracerProvider.builder().setSampler(Sampler.alwaysOff()).build(); + this.openTelemetrySdk = OpenTelemetrySdk.builder().setTracerProvider(sdkTracerProvider).build(); + this.otelTracer = openTelemetrySdk.getTracerProvider().get("io.micrometer.micrometer-tracing"); + this.otelCurrentTraceContext = new OtelCurrentTraceContext(); + this.tracer = new OtelTracer(otelTracer, otelCurrentTraceContext, event -> { + }, new OtelBaggageManager(otelCurrentTraceContext, Collections.emptyList(), Collections.emptyList())); + this.createdSpan = this.tracer.nextSpan().name("created-span"); + this.startedSpan = this.tracer.nextSpan().name("started-span").start(); + } + + } + + @Benchmark + public void micrometerTracing(MicrometerTracingState state, Blackhole blackhole) { + micrometerTracing(state.tracer, state.childSpanCount, blackhole); + } + + @Benchmark + public Span micrometerTracingNewSpan(MicrometerTracingState state) { + return micrometerTracingNewSpan(state.tracer); + } + + @Benchmark + public void micrometerTracingWithScope(MicrometerTracingState state, Blackhole blackhole) { + micrometerTracingWithScope(state.tracer, state.childSpanCount, blackhole); + } + + @State(Scope.Benchmark) + public static class OtelState { + + @Param({ "5" }) + public int childSpanCount; + + SdkTracerProvider sdkTracerProvider; + + OpenTelemetrySdk openTelemetrySdk; + + io.opentelemetry.api.trace.Tracer tracer; + + io.opentelemetry.api.trace.Span startedSpan; + + Context parentContext; + + @Setup + public void setup() { + this.sdkTracerProvider = SdkTracerProvider.builder().setSampler(Sampler.alwaysOff()).build(); + this.openTelemetrySdk = OpenTelemetrySdk.builder().setTracerProvider(sdkTracerProvider).build(); + this.tracer = openTelemetrySdk.getTracerProvider().get("io.micrometer.micrometer-tracing"); + this.startedSpan = this.tracer.spanBuilder("started-span").startSpan(); + this.parentContext = Context.root().with(this.startedSpan); + } + + } + + @Benchmark + public void otelTracing(OtelState state, Blackhole blackhole) { + io.opentelemetry.api.trace.Span parentSpan = state.tracer.spanBuilder("parent-span").startSpan(); + for (int i = 0; i < state.childSpanCount; i++) { + io.opentelemetry.api.trace.Span span = state.tracer.spanBuilder("new-span" + i) + .setParent(state.parentContext) + .startSpan(); + span.setAttribute("key", "value").addEvent("event").end(); + blackhole.consume(span); + } + parentSpan.end(); + blackhole.consume(parentSpan); + } + + @Benchmark + public io.opentelemetry.api.trace.Span otelTracingNewSpan(OtelState state) { + io.opentelemetry.api.trace.Span parentSpan = state.tracer.spanBuilder("child-span").startSpan(); + parentSpan.end(); + return parentSpan; + } + + @Benchmark + public void otelTracingWithScope(OtelState state, Blackhole blackhole) { + io.opentelemetry.api.trace.Span parentSpan = state.tracer.spanBuilder("parent-span").startSpan(); + try (io.opentelemetry.context.Scope scope = parentSpan.makeCurrent()) { + for (int i = 0; i < state.childSpanCount; i++) { + io.opentelemetry.api.trace.Span span = state.tracer.spanBuilder("new-span" + i).startSpan(); + try (io.opentelemetry.context.Scope scope2 = span.makeCurrent()) { + span.setAttribute("key", "value").addEvent("event"); + } + span.end(); + blackhole.consume(span); + } + } + parentSpan.end(); + blackhole.consume(parentSpan); + } + +} diff --git a/build.gradle b/build.gradle index 78a079b0..ec01cc80 100644 --- a/build.gradle +++ b/build.gradle @@ -16,6 +16,7 @@ buildscript { classpath 'io.spring.nohttp:nohttp-gradle:0.0.11' classpath 'io.github.gradle-nexus:publish-plugin:1.3.0' classpath 'io.spring.javaformat:spring-javaformat-gradle-plugin:0.0.39' + classpath 'me.champeau.jmh:jmh-gradle-plugin:0.7.1' constraints { classpath('org.ow2.asm:asm:7.3.1') { @@ -46,11 +47,16 @@ subprojects { apply plugin: 'signing' if (project.name != 'micrometer-tracing-bom') { - apply plugin: 'java-library' + if (project.name.contains('benchmarks')) { + apply plugin: 'java' + } else { + apply plugin: 'java-library' + } apply plugin: 'com.github.hierynomus.license' apply plugin: 'checkstyle' apply plugin: 'io.spring.nohttp' apply plugin: 'io.spring.javaformat' + apply plugin: 'me.champeau.jmh' java { // It is more idiomatic to define different features for different sets of optional @@ -70,6 +76,14 @@ subprojects { // JSR-305 only used for non-required meta-annotations optionalApi 'com.google.code.findbugs:jsr305:latest.release' checkstyle 'io.spring.javaformat:spring-javaformat-checkstyle:latest.release' + jmh 'org.openjdk.jmh:jmh-core:1.36' + jmh 'org.openjdk.jmh:jmh-generator-annprocess:1.36' + jmhAnnotationProcessor 'org.openjdk.jmh:jmh-generator-annprocess:1.36' + jmh 'net.sf.jopt-simple:jopt-simple' + } + + jmh { + duplicateClassesStrategy = DuplicatesStrategy.EXCLUDE } tasks { @@ -302,6 +316,7 @@ subprojects { description = 'Facade over tracing concepts' repositories { + maven { url 'https://repo.spring.io/snapshot' } // for latest micrometer snapshots mavenCentral() } diff --git a/buildscript-gradle.lockfile b/buildscript-gradle.lockfile index f38879b0..9fe233d7 100644 --- a/buildscript-gradle.lockfile +++ b/buildscript-gradle.lockfile @@ -51,13 +51,16 @@ io.spring.nohttp:nohttp-checkstyle:0.0.11=classpath io.spring.nohttp:nohttp-gradle:0.0.11=classpath io.spring.nohttp:nohttp:0.0.11=classpath joda-time:joda-time:2.10=classpath +me.champeau.jmh:jmh-gradle-plugin:0.7.1=classpath net.java.dev.jna:jna-platform:5.7.0=classpath net.java.dev.jna:jna:5.7.0=classpath net.java.dev.jna:platform:3.4.0=classpath +net.sf.jopt-simple:jopt-simple:5.0.4=classpath net.sf.saxon:Saxon-HE:9.9.1-7=classpath org.ajoberstar.grgit:grgit-core:4.0.2=classpath org.antlr:antlr-runtime:3.4=classpath org.antlr:antlr4-runtime:4.8-1=classpath +org.apache.commons:commons-math3:3.2=classpath org.apache.commons:commons-pool2:2.2=classpath org.apache.maven:maven-settings-builder:3.0.4=classpath org.apache.maven:maven-settings:3.0.4=classpath @@ -71,6 +74,7 @@ org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.20=classpath org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.20=classpath org.jetbrains.kotlin:kotlin-stdlib:1.7.20=classpath org.jetbrains:annotations:13.0=classpath +org.openjdk.jmh:jmh-core:1.36=classpath org.slf4j:slf4j-api:1.7.30=classpath org.sonatype.plexus:plexus-cipher:1.4=classpath org.sonatype.plexus:plexus-sec-dispatcher:1.3=classpath diff --git a/dependencies.gradle b/dependencies.gradle index c096ed2d..b9d3a7fb 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -32,7 +32,7 @@ def VERSIONS = [ ] def MICROMETER_PLATFORM_VERSIONS = [ - 'io.micrometer:micrometer-bom:1.11.1' + 'io.micrometer:micrometer-bom:1.11.2-SNAPSHOT' ] def PLATFORM_VERSIONS = [ diff --git a/micrometer-tracing-tests/micrometer-tracing-test/build.gradle b/micrometer-tracing-tests/micrometer-tracing-test/build.gradle index 5ed5b642..3273f028 100644 --- a/micrometer-tracing-tests/micrometer-tracing-test/build.gradle +++ b/micrometer-tracing-tests/micrometer-tracing-test/build.gradle @@ -14,4 +14,8 @@ dependencies { // aspects testImplementation 'org.springframework:spring-context' testImplementation 'org.aspectj:aspectjweaver' + + testImplementation 'io.projectreactor:reactor-core' + testImplementation 'io.projectreactor:reactor-core-micrometer' + testImplementation 'io.projectreactor:reactor-test' } diff --git a/micrometer-tracing-tests/micrometer-tracing-test/src/test/java/io/micrometer/tracing/test/contextpropagation/ObservationThreadLocalAccessorTests.java b/micrometer-tracing-tests/micrometer-tracing-test/src/test/java/io/micrometer/tracing/test/contextpropagation/ObservationThreadLocalAccessorTests.java new file mode 100644 index 00000000..53e81ab1 --- /dev/null +++ b/micrometer-tracing-tests/micrometer-tracing-test/src/test/java/io/micrometer/tracing/test/contextpropagation/ObservationThreadLocalAccessorTests.java @@ -0,0 +1,84 @@ +/* + * Copyright 2023 VMware, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.micrometer.tracing.test.contextpropagation; + +import io.micrometer.observation.ObservationRegistry; +import io.micrometer.observation.contextpropagation.ObservationThreadLocalAccessor; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import reactor.core.publisher.Hooks; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import java.util.concurrent.CompletableFuture; +import java.util.stream.Stream; + +import static reactor.core.observability.micrometer.Micrometer.observation; + +class ObservationThreadLocalAccessorTests { + + static ObservationRegistry original = ObservationThreadLocalAccessor.getInstance().getObservationRegistry(); + + @AfterEach + void cleanup() { + ObservationThreadLocalAccessor.getInstance().setObservationRegistry(original); + Hooks.disableAutomaticContextPropagation(); + } + + @ParameterizedTest( + name = "<{index}> Reactor propagation enabled <{0}>, ObservationRegistry in OTLA <{1}>, ObservationRegistry in TAP <{2}>") + @MethodSource("argumentsForReactorMicrometerInterop") + void monoWithoutException(boolean enableAutomaticPropagation, ObservationRegistry registryInOtla, + ObservationRegistry registryInTap) { + if (enableAutomaticPropagation) { + Hooks.enableAutomaticContextPropagation(); + } + else { + Hooks.disableAutomaticContextPropagation(); + } + + if (registryInOtla != null) { + ObservationThreadLocalAccessor.getInstance().setObservationRegistry(registryInOtla); + } + + final Mono response = Mono.fromFuture(CompletableFuture.supplyAsync(() -> "OK")) + .name("mono-without-exception") + .tap(observation(registryInTap)) + .thenReturn("OK"); + + StepVerifier.create(response).expectNext("OK").expectComplete().verify(); + } + + private static Stream argumentsForReactorMicrometerInterop() { + return Stream.of(Arguments.of(true, null, ObservationRegistry.NOOP), + Arguments.of(true, observationRegistryWithHandler(), ObservationRegistry.NOOP), + Arguments.of(true, ObservationRegistry.NOOP, observationRegistryWithHandler()), + Arguments.of(true, observationRegistryWithHandler(), observationRegistryWithHandler()), + Arguments.of(false, null, ObservationRegistry.NOOP), + Arguments.of(false, observationRegistryWithHandler(), ObservationRegistry.NOOP), + Arguments.of(false, ObservationRegistry.NOOP, observationRegistryWithHandler()), + Arguments.of(false, observationRegistryWithHandler(), observationRegistryWithHandler())); + } + + private static ObservationRegistry observationRegistryWithHandler() { + ObservationRegistry registry = ObservationRegistry.create(); + registry.observationConfig().observationHandler(context -> true); + return registry; + } + +} diff --git a/settings.gradle b/settings.gradle index 097128d1..35927bbe 100644 --- a/settings.gradle +++ b/settings.gradle @@ -5,7 +5,7 @@ pluginManagement { } plugins { - id 'com.gradle.enterprise' version '3.13.3' + id 'com.gradle.enterprise' version '3.13.4' id 'io.spring.ge.conventions' version '0.0.13' id 'org.gradle.toolchains.foojay-resolver-convention' version '0.4.0' } @@ -21,7 +21,7 @@ gradleEnterprise { server = 'https://ge.micrometer.io' } -include 'micrometer-tracing', 'micrometer-tracing-bom' +include 'micrometer-tracing', 'micrometer-tracing-bom', 'benchmarks' ['brave', 'otel'].each { bridge -> include "micrometer-tracing-bridge-$bridge"