From 059debe2aa0c8699f18c4800fb7902b1bd45f587 Mon Sep 17 00:00:00 2001 From: Clint Checketts Date: Sat, 11 Nov 2017 19:51:22 -0700 Subject: [PATCH] Create TracingTimer that leverages OpenTracing --- micrometer-core/build.gradle | 5 + .../io/micrometer/core/instrument/Timer.java | 2 +- .../core/instrument/TracingTimer.java | 124 ++++++++++++++++++ .../core/instrument/TracingTimerTest.java | 65 +++++++++ 4 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 micrometer-core/src/main/java/io/micrometer/core/instrument/TracingTimer.java create mode 100644 micrometer-core/src/test/java/io/micrometer/core/instrument/TracingTimerTest.java diff --git a/micrometer-core/build.gradle b/micrometer-core/build.gradle index 410aa6c71a..eb76016b55 100644 --- a/micrometer-core/build.gradle +++ b/micrometer-core/build.gradle @@ -36,6 +36,11 @@ dependencies { compile 'com.squareup.okhttp3:okhttp:3.9.0',optional + //tracing + compile 'io.opentracing:opentracing-api:0.30.0', optional + testCompile 'io.opentracing:opentracing-mock:0.30.0' + testCompile 'io.opentracing:opentracing-util:0.30.0' + testCompile 'io.projectreactor:reactor-test:3.1.0.RELEASE' testCompile 'io.projectreactor.ipc:reactor-netty:0.7.0.RELEASE' diff --git a/micrometer-core/src/main/java/io/micrometer/core/instrument/Timer.java b/micrometer-core/src/main/java/io/micrometer/core/instrument/Timer.java index 2352a6c8f0..a2561fb4e2 100644 --- a/micrometer-core/src/main/java/io/micrometer/core/instrument/Timer.java +++ b/micrometer-core/src/main/java/io/micrometer/core/instrument/Timer.java @@ -139,7 +139,7 @@ class Builder { private String description; private final HistogramConfig.Builder histogramConfigBuilder; - private Builder(String name) { + Builder(String name) { this.name = name; this.histogramConfigBuilder = new HistogramConfig.Builder(); minimumExpectedValue(Duration.ofMillis(1)); diff --git a/micrometer-core/src/main/java/io/micrometer/core/instrument/TracingTimer.java b/micrometer-core/src/main/java/io/micrometer/core/instrument/TracingTimer.java new file mode 100644 index 0000000000..13160eecfc --- /dev/null +++ b/micrometer-core/src/main/java/io/micrometer/core/instrument/TracingTimer.java @@ -0,0 +1,124 @@ +/** + * Copyright 2017 Pivotal Software, 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 + *

+ * http://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.core.instrument; + +import io.opentracing.ActiveSpan; +import io.opentracing.Tracer; + +import java.util.concurrent.Callable; +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; + +public class TracingTimer implements Timer{ + + static Builder builder(String name, Tracer tracer) { + return new Builder(name, tracer); + } + + static class Builder extends Timer.Builder{ + private final Tracer tracer; + + Builder(String name, Tracer tracer) { + super(name); + this.tracer = tracer; + } + + @Override + public Timer register(MeterRegistry registry) { + return new TracingTimer(super.register(registry), tracer); + } + } + + private final Timer delegate; + private final Tracer tracer; + + TracingTimer(Timer delegate, Tracer tracer) { + this.delegate = delegate; + this.tracer = tracer; + } + + private ActiveSpan createSpan() { + Tracer.SpanBuilder spanBuilder = tracer.buildSpan(getId().getName()); + getId().getTags().forEach(t -> spanBuilder.withTag(t.getKey(), t.getValue())); + return spanBuilder.startActive(); + } + + + @Override + public T record(Supplier f) { + try(@SuppressWarnings("unused") ActiveSpan span = createSpan()){ + return delegate.record(f); + } + } + + @Override + public T recordCallable(Callable f) throws Exception { + try(@SuppressWarnings("unused") ActiveSpan span = createSpan()) { + return delegate.recordCallable(f); + } + } + + @Override + public void record(Runnable f) { + try(@SuppressWarnings("unused") ActiveSpan span = createSpan()) { + delegate.record(f); + } + } + + @Override + public Callable wrap(Callable f) { + return () -> { + try(@SuppressWarnings("unused") ActiveSpan span = createSpan()) { + return delegate.wrap(f).call(); + } + }; + } + + @Override + public void record(long amount, TimeUnit unit) { + delegate.record(amount, unit); + } + + @Override + public long count() { + return delegate.count(); + } + + @Override + public double totalTime(TimeUnit unit) { + return delegate.totalTime(unit); + } + + @Override + public double max(TimeUnit unit) { + return delegate.max(unit); + } + + @Override + public double percentile(double percentile, TimeUnit unit) { + return delegate.percentile(percentile, unit); + } + + @Override + public double histogramCountAtValue(long valueNanos) { + return delegate.histogramCountAtValue(valueNanos); + } + + @Override + public Id getId() { + return delegate.getId(); + } +} diff --git a/micrometer-core/src/test/java/io/micrometer/core/instrument/TracingTimerTest.java b/micrometer-core/src/test/java/io/micrometer/core/instrument/TracingTimerTest.java new file mode 100644 index 0000000000..066b49857e --- /dev/null +++ b/micrometer-core/src/test/java/io/micrometer/core/instrument/TracingTimerTest.java @@ -0,0 +1,65 @@ +/** + * Copyright 2017 Pivotal Software, 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 + *

+ * http://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.core.instrument; + +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; +import io.opentracing.mock.MockSpan; +import io.opentracing.mock.MockTracer; +import io.opentracing.util.ThreadLocalActiveSpanSource; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class TracingTimerTest { + + private MockTracer tracer; + private SimpleMeterRegistry registry; + + @BeforeEach + void setup(){ + tracer = new MockTracer(new ThreadLocalActiveSpanSource(), MockTracer.Propagator.TEXT_MAP); + registry = new SimpleMeterRegistry(); + registry.config().commonTags("commonTag1", "commonVal1"); + } + + @Test + void tracingTimer() { + TracingTimer.builder("trace.outer.timer", tracer).tags("testTag1","testVal1").register(registry).record(() -> { + TracingTimer.builder("trace.inner.timer", tracer).tags("testTag2","testVal2").register(registry).record(() -> { + //Nothing to do here + }); + }); + + List mockSpans = tracer.finishedSpans(); + assertThat(mockSpans).hasSize(2); + + MockSpan innerSpan = mockSpans.get(0); + assertThat(innerSpan.operationName()).isEqualTo("trace.inner.timer"); + assertThat(innerSpan.tags().get("commonTag1")).describedAs("Common tags are applied").isEqualTo("commonVal1"); + assertThat(innerSpan.parentId()).isEqualTo(2L); + + MockSpan outerSpan = mockSpans.get(1); + assertThat(outerSpan.operationName()).isEqualTo("trace.outer.timer"); + assertThat(outerSpan.tags()).hasSize(2); + assertThat(outerSpan.tags().get("testTag1")).isEqualTo("testVal1"); + + + } + +}