diff --git a/build.gradle b/build.gradle index 54552524cd..ca3f222346 100644 --- a/build.gradle +++ b/build.gradle @@ -91,6 +91,10 @@ ext { // Used only in tests contextPropagationVersion = '1.0.0-RC1' //optional baseline + // Used only in examples + braveVersion = '5.14.1' + zipkinSenderVersion = '2.16.3' + jsr305Version = '3.0.2' // Logging diff --git a/docs/asciidoc/http-client.adoc b/docs/asciidoc/http-client.adoc index 6d16005722..e61395ba5e 100644 --- a/docs/asciidoc/http-client.adoc +++ b/docs/asciidoc/http-client.adoc @@ -432,6 +432,42 @@ include::{examplesdir}/metrics/custom/Application.java[lines=18..35] <1> Enables HTTP client metrics and provides {javadoc}/reactor/netty5/http/client/HttpClientMetricsRecorder.html[`HttpClientMetricsRecorder`] implementation. ==== +== Tracing +The HTTP client supports built-in integration with https://micrometer.io/docs/tracing[`Micrometer Tracing`]. + +The following table provides information for the HTTP client spans: + +[width="100%",options="header"] +|======= +| contextual name | description +| HTTP | Information and total time for the request. +See <>. +| hostname resolution | Information and time spent for resolving the address. +See <>. +| connect | Information and time spent for connecting to the remote address. +See <>. +| tls handshake | Information and time spent for TLS handshake. +See <>. +|======= + +The following example enables that integration. This concrete example uses `Brave` and reports the information to `Zipkin`. +See the https://micrometer.io/docs/tracing#_micrometer_tracing_opentelemetry_setup[`Micrometer Tracing`] documentation for `OpenTelemetry` setup. + +==== +[source,java,indent=0] +.{examplesdir}/tracing/Application.java +---- +include::{examplesdir}/tracing/Application.java[lines=18..90] +---- +<1> Initializes Brave, Zipkin, and the Observation registry. +<2> Templated URIs are used as an URI tag value when possible. +<3> Enables the built-in integration with Micrometer. +==== + +The result in `Zipkin` looks like: + +image::images/http-client-tracing.png[] + == Unix Domain Sockets The `HTTP` client supports Unix Domain Sockets (UDS) for all transports (native and NIO). diff --git a/docs/asciidoc/http-server.adoc b/docs/asciidoc/http-server.adoc index 217660f64c..1feb9aaf07 100644 --- a/docs/asciidoc/http-server.adoc +++ b/docs/asciidoc/http-server.adoc @@ -614,6 +614,36 @@ include::{examplesdir}/metrics/custom/Application.java[lines=18..41] <1> Enables HTTP server metrics and provides {javadoc}/reactor/netty5/http/server/HttpServerMetricsRecorder.html[`HttpServerMetricsRecorder`] implementation. ==== +== Tracing +The HTTP server supports built-in integration with https://micrometer.io/docs/tracing[`Micrometer Tracing`]. + +The following table provides information for the HTTP server spans: + +[width="100%",options="header"] +|======= +| contextual name | description +| _ | Information and total time for the request. +See <>. +|======= + +The following example enables that integration. This concrete example uses `Brave` and reports the information to `Zipkin`. +See the https://micrometer.io/docs/tracing#_micrometer_tracing_opentelemetry_setup[`Micrometer Tracing`] documentation for `OpenTelemetry` setup. + +==== +[source,java,indent=0] +.{examplesdir}/tracing/Application.java +---- +include::{examplesdir}/tracing/Application.java[lines=18..91] +---- +<1> Initializes Brave, Zipkin, and the Observation registry. +<2> Templated URIs are used as an URI tag value when possible. +<3> Enables the built-in integration with Micrometer. +==== + +The result in `Zipkin` looks like: + +image::images/http-server-tracing.png[] + == Unix Domain Sockets The `HTTP` server supports Unix Domain Sockets (UDS) for all transports (native and NIO). diff --git a/docs/asciidoc/images/http-client-tracing.png b/docs/asciidoc/images/http-client-tracing.png new file mode 100644 index 0000000000..9d9611ab47 Binary files /dev/null and b/docs/asciidoc/images/http-client-tracing.png differ diff --git a/docs/asciidoc/images/http-server-tracing.png b/docs/asciidoc/images/http-server-tracing.png new file mode 100644 index 0000000000..ff363b1d90 Binary files /dev/null and b/docs/asciidoc/images/http-server-tracing.png differ diff --git a/docs/asciidoc/images/tcp-client-tracing.png b/docs/asciidoc/images/tcp-client-tracing.png new file mode 100644 index 0000000000..b7b10154ef Binary files /dev/null and b/docs/asciidoc/images/tcp-client-tracing.png differ diff --git a/docs/asciidoc/images/tcp-server-tracing.png b/docs/asciidoc/images/tcp-server-tracing.png new file mode 100644 index 0000000000..aa5c75f553 Binary files /dev/null and b/docs/asciidoc/images/tcp-server-tracing.png differ diff --git a/docs/asciidoc/tcp-client.adoc b/docs/asciidoc/tcp-client.adoc index dbec78cfb6..ce05282907 100644 --- a/docs/asciidoc/tcp-client.adoc +++ b/docs/asciidoc/tcp-client.adoc @@ -322,6 +322,39 @@ include::{examplesdir}/metrics/custom/Application.java[lines=18..37] <1> Enables TCP client metrics and provides {javadoc}/reactor/netty5/channel/ChannelMetricsRecorder.html[`ChannelMetricsRecorder`] implementation. ==== +== Tracing +The TCP client supports built-in integration with https://micrometer.io/docs/tracing[`Micrometer Tracing`]. + +The following table provides information for the TCP client spans: + +[width="100%",options="header"] +|======= +| contextual name | description +| hostname resolution | Information and time spent for resolving the address. +See <>. +| connect | Information and time spent for connecting to the remote address. +See <>. +| tls handshake | Information and time spent for TLS handshake. +See <>. +|======= + +The following example enables that integration. This concrete example uses `Brave` and reports the information to `Zipkin`. +See the https://micrometer.io/docs/tracing#_micrometer_tracing_opentelemetry_setup[`Micrometer Tracing`] documentation for `OpenTelemetry` setup. + +==== +[source,java,indent=0] +.{examplesdir}/tracing/Application.java +---- +include::{examplesdir}/tracing/Application.java[lines=18..81] +---- +<1> Initializes Brave, Zipkin, and the Observation registry. +<2> Enables the built-in integration with Micrometer. +==== + +The result in `Zipkin` looks like: + +image::images/tcp-client-tracing.png[] + == Unix Domain Sockets The `TCP` client supports Unix Domain Sockets (UDS) for all transports (native and NIO). diff --git a/docs/asciidoc/tcp-server.adoc b/docs/asciidoc/tcp-server.adoc index 9bab3dd888..284f3bbe6a 100644 --- a/docs/asciidoc/tcp-server.adoc +++ b/docs/asciidoc/tcp-server.adoc @@ -294,6 +294,35 @@ include::{examplesdir}/metrics/custom/Application.java[lines=18..35] <1> Enables TCP server metrics and provides {javadoc}/reactor/netty5/channel/ChannelMetricsRecorder.html[`ChannelMetricsRecorder`] implementation. ==== +== Tracing +The TCP server supports built-in integration with https://micrometer.io/docs/tracing[`Micrometer Tracing`]. + +The following table provides information for the TCP server spans: + +[width="100%",options="header"] +|======= +| contextual name | description +| tls handshake | Information and time spent for TLS handshake. +See <>. +|======= + +The following example enables that integration. This concrete example uses `Brave` and reports the information to `Zipkin`. +See the https://micrometer.io/docs/tracing#_micrometer_tracing_opentelemetry_setup[`Micrometer Tracing`] documentation for `OpenTelemetry` setup. + +==== +[source,java,indent=0] +.{examplesdir}/tracing/Application.java +---- +include::{examplesdir}/tracing/Application.java[lines=18..81] +---- +<1> Initializes Brave, Zipkin, and the Observation registry. +<2> Enables the built-in integration with Micrometer. +==== + +The result in `Zipkin` looks like: + +image::images/tcp-server-tracing.png[] + == Unix Domain Sockets The `TCP` server supports Unix Domain Sockets (UDS) for all transports (native and NIO). diff --git a/reactor-netty5-examples/build.gradle b/reactor-netty5-examples/build.gradle index 84d0fbe021..bbd2bde211 100644 --- a/reactor-netty5-examples/build.gradle +++ b/reactor-netty5-examples/build.gradle @@ -19,6 +19,10 @@ dependencies { api "com.fasterxml.jackson.core:jackson-databind:$jacksonDatabindVersion" api "io.micrometer:micrometer-core:$micrometerVersion" + api "io.micrometer:micrometer-tracing:$micrometerTracingVersion" + api "io.micrometer:micrometer-tracing-bridge-brave:$micrometerTracingVersion" + api "io.zipkin.brave:brave:$braveVersion" + api "io.zipkin.reporter2:zipkin-sender-urlconnection:$zipkinSenderVersion" api "io.netty:netty5-transport-native-epoll:$nettyVersion:linux-x86_64" diff --git a/reactor-netty5-examples/src/main/java/reactor/netty5/examples/documentation/http/client/tracing/Application.java b/reactor-netty5-examples/src/main/java/reactor/netty5/examples/documentation/http/client/tracing/Application.java new file mode 100644 index 0000000000..828e21fac4 --- /dev/null +++ b/reactor-netty5-examples/src/main/java/reactor/netty5/examples/documentation/http/client/tracing/Application.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2022 VMware, Inc. or its affiliates, All Rights Reserved. + * + * 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 reactor.netty5.examples.documentation.http.client.tracing; + +import brave.Tracing; +import brave.handler.SpanHandler; +import brave.propagation.StrictCurrentTraceContext; +import brave.sampler.Sampler; +import io.micrometer.tracing.CurrentTraceContext; +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.BravePropagator; +import io.micrometer.tracing.brave.bridge.BraveTracer; +import io.micrometer.tracing.propagation.Propagator; +import reactor.netty5.http.client.HttpClient; +import reactor.netty5.http.observability.ReactorNettyPropagatingSenderTracingObservationHandler; +import reactor.netty5.observability.ReactorNettyTracingObservationHandler; +import zipkin2.reporter.AsyncReporter; +import zipkin2.reporter.brave.ZipkinSpanHandler; +import zipkin2.reporter.urlconnection.URLConnectionSender; + +import static reactor.netty5.Metrics.OBSERVATION_REGISTRY; + +public class Application { + + public static void main(String[] args) { + init(); //<1> + + HttpClient client = + HttpClient.create() + .metrics(true, s -> { + if (s.startsWith("/stream/")) { //<2> + return "/stream/{n}"; + } + return s; + }); //<3> + + client.get() + .uri("https://httpbin.org/stream/3") + .responseContent() + .blockLast(); + } + + /** + * This setup is based on + * Micrometer Tracing Brave Setup + */ + static void init() { + SpanHandler spanHandler = ZipkinSpanHandler + .create(AsyncReporter.create(URLConnectionSender.create("http://localhost:9411/api/v2/spans"))); + + StrictCurrentTraceContext braveCurrentTraceContext = StrictCurrentTraceContext.create(); + + CurrentTraceContext bridgeContext = new BraveCurrentTraceContext(braveCurrentTraceContext); + + Tracing tracing = + Tracing.newBuilder() + .currentTraceContext(braveCurrentTraceContext) + .supportsJoin(false) + .traceId128Bit(true) + .sampler(Sampler.ALWAYS_SAMPLE) + .addSpanHandler(spanHandler) + .localServiceName("reactor-netty-examples") + .build(); + + brave.Tracer braveTracer = tracing.tracer(); + + Tracer tracer = new BraveTracer(braveTracer, bridgeContext, new BraveBaggageManager()); + + Propagator propagator = new BravePropagator(tracing); + + OBSERVATION_REGISTRY.observationConfig() + .observationHandler(new ReactorNettyPropagatingSenderTracingObservationHandler(tracer, propagator)) + .observationHandler(new ReactorNettyTracingObservationHandler(tracer)); + } +} \ No newline at end of file diff --git a/reactor-netty5-examples/src/main/java/reactor/netty5/examples/documentation/http/server/tracing/Application.java b/reactor-netty5-examples/src/main/java/reactor/netty5/examples/documentation/http/server/tracing/Application.java new file mode 100644 index 0000000000..f38ed6c71e --- /dev/null +++ b/reactor-netty5-examples/src/main/java/reactor/netty5/examples/documentation/http/server/tracing/Application.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2022 VMware, Inc. or its affiliates, All Rights Reserved. + * + * 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 reactor.netty5.examples.documentation.http.server.tracing; + +import brave.Tracing; +import brave.handler.SpanHandler; +import brave.propagation.StrictCurrentTraceContext; +import brave.sampler.Sampler; +import io.micrometer.tracing.CurrentTraceContext; +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.BravePropagator; +import io.micrometer.tracing.brave.bridge.BraveTracer; +import io.micrometer.tracing.propagation.Propagator; +import reactor.core.publisher.Mono; +import reactor.netty5.DisposableServer; +import reactor.netty5.http.observability.ReactorNettyPropagatingReceiverTracingObservationHandler; +import reactor.netty5.http.server.HttpServer; +import zipkin2.reporter.AsyncReporter; +import zipkin2.reporter.brave.ZipkinSpanHandler; +import zipkin2.reporter.urlconnection.URLConnectionSender; + +import static reactor.netty5.Metrics.OBSERVATION_REGISTRY; + +public class Application { + + public static void main(String[] args) { + init(); //<1> + + DisposableServer server = + HttpServer.create() + .metrics(true, s -> { + if (s.startsWith("/stream/")) { //<2> + return "/stream/{n}"; + } + return s; + }) //<3> + .route(r -> r.get("/stream/{n}", + (req, res) -> res.sendString(Mono.just(req.param("n"))))) + .bindNow(); + + server.onDispose() + .block(); + } + + /** + * This setup is based on + * Micrometer Tracing Brave Setup + */ + static void init() { + SpanHandler spanHandler = ZipkinSpanHandler + .create(AsyncReporter.create(URLConnectionSender.create("http://localhost:9411/api/v2/spans"))); + + StrictCurrentTraceContext braveCurrentTraceContext = StrictCurrentTraceContext.create(); + + CurrentTraceContext bridgeContext = new BraveCurrentTraceContext(braveCurrentTraceContext); + + Tracing tracing = + Tracing.newBuilder() + .currentTraceContext(braveCurrentTraceContext) + .supportsJoin(false) + .traceId128Bit(true) + .sampler(Sampler.ALWAYS_SAMPLE) + .addSpanHandler(spanHandler) + .localServiceName("reactor-netty-examples") + .build(); + + brave.Tracer braveTracer = tracing.tracer(); + + Tracer tracer = new BraveTracer(braveTracer, bridgeContext, new BraveBaggageManager()); + + Propagator propagator = new BravePropagator(tracing); + + OBSERVATION_REGISTRY.observationConfig() + .observationHandler(new ReactorNettyPropagatingReceiverTracingObservationHandler(tracer, propagator)); + } +} \ No newline at end of file diff --git a/reactor-netty5-examples/src/main/java/reactor/netty5/examples/documentation/tcp/client/tracing/Application.java b/reactor-netty5-examples/src/main/java/reactor/netty5/examples/documentation/tcp/client/tracing/Application.java new file mode 100644 index 0000000000..a881c1f6c7 --- /dev/null +++ b/reactor-netty5-examples/src/main/java/reactor/netty5/examples/documentation/tcp/client/tracing/Application.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2022 VMware, Inc. or its affiliates, All Rights Reserved. + * + * 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 reactor.netty5.examples.documentation.tcp.client.tracing; + +import brave.Tracing; +import brave.handler.SpanHandler; +import brave.propagation.StrictCurrentTraceContext; +import brave.sampler.Sampler; +import io.micrometer.tracing.CurrentTraceContext; +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 reactor.netty5.Connection; +import reactor.netty5.observability.ReactorNettyTracingObservationHandler; +import reactor.netty5.tcp.TcpClient; +import zipkin2.reporter.AsyncReporter; +import zipkin2.reporter.brave.ZipkinSpanHandler; +import zipkin2.reporter.urlconnection.URLConnectionSender; + +import static reactor.netty5.Metrics.OBSERVATION_REGISTRY; + +public class Application { + + public static void main(String[] args) { + init(); //<1> + + Connection connection = + TcpClient.create() + .host("example.com") + .port(80) + .metrics(true) //<1> + .connectNow(); + + connection.onDispose() + .block(); + } + + /** + * This setup is based on + * Micrometer Tracing Brave Setup + */ + static void init() { + SpanHandler spanHandler = ZipkinSpanHandler + .create(AsyncReporter.create(URLConnectionSender.create("http://localhost:9411/api/v2/spans"))); + + StrictCurrentTraceContext braveCurrentTraceContext = StrictCurrentTraceContext.create(); + + CurrentTraceContext bridgeContext = new BraveCurrentTraceContext(braveCurrentTraceContext); + + Tracing tracing = + Tracing.newBuilder() + .currentTraceContext(braveCurrentTraceContext) + .supportsJoin(false) + .traceId128Bit(true) + .sampler(Sampler.ALWAYS_SAMPLE) + .addSpanHandler(spanHandler) + .localServiceName("reactor-netty-examples") + .build(); + + brave.Tracer braveTracer = tracing.tracer(); + + Tracer tracer = new BraveTracer(braveTracer, bridgeContext, new BraveBaggageManager()); + + OBSERVATION_REGISTRY.observationConfig() + .observationHandler(new ReactorNettyTracingObservationHandler(tracer)); + } +} \ No newline at end of file diff --git a/reactor-netty5-examples/src/main/java/reactor/netty5/examples/documentation/tcp/server/tracing/Application.java b/reactor-netty5-examples/src/main/java/reactor/netty5/examples/documentation/tcp/server/tracing/Application.java new file mode 100644 index 0000000000..25c59828a9 --- /dev/null +++ b/reactor-netty5-examples/src/main/java/reactor/netty5/examples/documentation/tcp/server/tracing/Application.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2022 VMware, Inc. or its affiliates, All Rights Reserved. + * + * 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 reactor.netty5.examples.documentation.tcp.server.tracing; + +import brave.Tracing; +import brave.handler.SpanHandler; +import brave.propagation.StrictCurrentTraceContext; +import brave.sampler.Sampler; +import io.micrometer.tracing.CurrentTraceContext; +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 reactor.core.publisher.Mono; +import reactor.netty5.DisposableServer; +import reactor.netty5.observability.ReactorNettyTracingObservationHandler; +import reactor.netty5.tcp.TcpServer; +import zipkin2.reporter.AsyncReporter; +import zipkin2.reporter.brave.ZipkinSpanHandler; +import zipkin2.reporter.urlconnection.URLConnectionSender; + +import static reactor.netty5.Metrics.OBSERVATION_REGISTRY; + +public class Application { + + public static void main(String[] args) { + init(); //<1> + + DisposableServer server = + TcpServer.create() + .metrics(true) //<2> + .handle((inbound, outbound) -> outbound.sendString(Mono.just("hello"))) + .bindNow(); + + server.onDispose() + .block(); + } + + /** + * This setup is based on + * Micrometer Tracing Brave Setup + */ + static void init() { + SpanHandler spanHandler = ZipkinSpanHandler + .create(AsyncReporter.create(URLConnectionSender.create("http://localhost:9411/api/v2/spans"))); + + StrictCurrentTraceContext braveCurrentTraceContext = StrictCurrentTraceContext.create(); + + CurrentTraceContext bridgeContext = new BraveCurrentTraceContext(braveCurrentTraceContext); + + Tracing tracing = + Tracing.newBuilder() + .currentTraceContext(braveCurrentTraceContext) + .supportsJoin(false) + .traceId128Bit(true) + .sampler(Sampler.ALWAYS_SAMPLE) + .addSpanHandler(spanHandler) + .localServiceName("reactor-netty-examples") + .build(); + + brave.Tracer braveTracer = tracing.tracer(); + + Tracer tracer = new BraveTracer(braveTracer, bridgeContext, new BraveBaggageManager()); + + OBSERVATION_REGISTRY.observationConfig() + .observationHandler(new ReactorNettyTracingObservationHandler(tracer)); + } +} \ No newline at end of file