Skip to content

Commit

Permalink
[tracing] Add easy support for Jaeger tracing
Browse files Browse the repository at this point in the history
  • Loading branch information
shs96c committed Feb 4, 2020
1 parent 16a703c commit f9ab927
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 4 deletions.
3 changes: 2 additions & 1 deletion java/maven_deps.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ def selenium_java_deps():
"com.google.auto.service:auto-service-annotations:1.0-rc6",
"com.squareup.okhttp3:okhttp:4.3.0",
"com.typesafe.netty:netty-reactive-streams:2.0.4",
# "io.grpc:grpc-api:1.24.0",
"io.lettuce:lettuce-core:5.2.1.RELEASE",
"io.netty:netty-buffer:%s" % netty_version,
"io.netty:netty-codec-haproxy:%s" % netty_version,
Expand All @@ -25,7 +26,7 @@ def selenium_java_deps():
"io.netty:netty-transport:%s" % netty_version,
"io.opentelemetry:opentelemetry-api:0.2.0",
"io.opentelemetry:opentelemetry-exporters-inmemory:0.2.0",
"io.opentelemetry:opentelemetry-exporters-jaeger:0.2.0",
# "io.opentelemetry:opentelemetry-exporters-jaeger:0.2.0",
"io.opentelemetry:opentelemetry-exporters-logging:0.2.0",
"io.opentelemetry:opentelemetry-sdk:0.2.0",
"it.ozimov:embedded-redis:0.7.2",
Expand Down
1 change: 1 addition & 0 deletions java/server/src/org/openqa/selenium/grid/log/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ java_library(
"//java/client/src/org/openqa/selenium/json",
"//java/client/src/org/openqa/selenium/remote",
"//java/server/src/org/openqa/selenium/grid/config",
# artifact("io.grpc:grpc-api"),
artifact("io.opentelemetry:opentelemetry-api"),
# artifact("io.opentelemetry:opentelemetry-exporters-jaeger"),
artifact("io.opentelemetry:opentelemetry-exporters-logging"),
Expand Down
91 changes: 91 additions & 0 deletions java/server/src/org/openqa/selenium/grid/log/JaegerTracing.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package org.openqa.selenium.grid.log;

import io.opentelemetry.sdk.trace.export.SpanExporter;

import java.lang.reflect.Method;

/**
* We use an awful lof of reflection here because it's the only way we can
* get this to work without requiring the selenium server take a dependency
* on Jaeger, which may not be needed in all cases.
*/
class JaegerTracing {

static SpanExporter findJaegerExporter() {
String host = System.getProperty("JAEGER_AGENT_HOST");
if (host == null) {
return null;
}

String rawPort = System.getProperty("JAEGER_AGENT_PORT");
int port = -1;
try {
port = Integer.parseInt(rawPort);
} catch (NumberFormatException ignored) {
return null;
}
if (port == -1) {
return null;
}

try {
Object jaegerChannel = createManagedChannel(host, port);
SpanExporter toReturn = (SpanExporter) createJaegerGrpcSpanExporter(jaegerChannel);

if (toReturn != null) {
System.out.printf("Attaching Jaeger tracing to %s:%s\n", host, port);
}

return toReturn;
} catch (ReflectiveOperationException e) {
return null;
}
}

private static Object createManagedChannel(String host, int port) throws ReflectiveOperationException {
// Equivalent to:
// ManagedChannelBuilder.forAddress(host, port).usePlaintext().build();

ClassLoader cl = Thread.currentThread().getContextClassLoader();

Class<?> builderClazz = Class.forName("io.grpc.ManagedChannelBuilder", true, cl);
Method forAddress = builderClazz.getMethod("forAddress", String.class, int.class);
Object value = forAddress.invoke(null, host, port);

Method usePlaintext = builderClazz.getMethod("usePlaintext");
value = usePlaintext.invoke(value);

Method build = builderClazz.getMethod("build");
return build.invoke(value);
}

private static Object createJaegerGrpcSpanExporter(Object jaegerChannel) throws ReflectiveOperationException {
// Equivalent to:
// return JaegerGrpcSpanExporter.newBuilder()
// .setServiceName("selenium")
// .setChannel(jaegerChannel)
// .setDeadline(30000)
// .build();

ClassLoader cl = Thread.currentThread().getContextClassLoader();

Class<?> exporterClazz = Class.forName("io.opentelemetry.exporters.jaeger.JaegerGrpcSpanExporter", true, cl);
Method newBuilder = exporterClazz.getMethod("newBuilder");
Object builderObj = newBuilder.invoke(exporterClazz);

Class<?> builderClazz = builderObj.getClass();

Method setServiceName = builderClazz.getMethod("setServiceName", String.class);
builderObj = setServiceName.invoke(builderObj, System.getProperty("JAEGER_SERVICE_NAME", "selenium"));

Class<?> managedChannelClazz = Class.forName("io.grpc.ManagedChannel", true, cl);
Method setChannel = builderClazz.getMethod("setChannel", managedChannelClazz);
builderObj = setChannel.invoke(builderObj, jaegerChannel);

Method setDeadline = builderClazz.getMethod("setDeadline", long.class);
builderObj = setDeadline.invoke(builderObj, 30000);

Method build = builderClazz.getMethod("build");
return build.invoke(builderObj);
}
}
19 changes: 16 additions & 3 deletions java/server/src/org/openqa/selenium/grid/log/LoggingOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,18 @@

import io.opentelemetry.exporters.logging.LoggingExporter;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.trace.MultiSpanProcessor;
import io.opentelemetry.sdk.trace.SpanProcessor;
import io.opentelemetry.sdk.trace.TracerSdkFactory;
import io.opentelemetry.sdk.trace.export.SimpleSpansProcessor;
import io.opentelemetry.sdk.trace.export.SpanExporter;
import io.opentelemetry.trace.Tracer;
import org.openqa.selenium.grid.config.Config;

import java.util.Arrays;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.logging.Handler;
import java.util.logging.LogManager;
Expand All @@ -49,11 +54,19 @@ public boolean isUsingPlainLogs() {

public Tracer getTracer() {
TracerSdkFactory tracerFactory = OpenTelemetrySdk.getTracerFactory();
tracerFactory.addSpanProcessor(SimpleSpansProcessor.newBuilder(new LoggingExporter()).build());

List<SpanProcessor> exporters = new LinkedList<>();
// exporters.add(SimpleSpansProcessor.newBuilder(new LoggingExporter()).build());

// 2020-01-28: The Jaeger exporter doesn't yet have a
// `TracerFactoryProvider`, so we shall look up the class directly, and
// beg for forgiveness.
// `TracerFactoryProvider`, so we shall look up the class using
// reflection, and beg for forgiveness later.
SpanExporter maybeJaeger = JaegerTracing.findJaegerExporter();
if (maybeJaeger != null) {
exporters.add(SimpleSpansProcessor.newBuilder(maybeJaeger).build());
}

tracerFactory.addSpanProcessor(MultiSpanProcessor.create(exporters));

return tracerFactory.get("default");
}
Expand Down

0 comments on commit f9ab927

Please sign in to comment.