Skip to content

Commit

Permalink
[tracing] Use OT provided mechanisms for configuring OT
Browse files Browse the repository at this point in the history
Notably, we now use OpenTelemetry's own reflection-based mechanism for
loading tracers. This means we have removed our custom code for
setting things up for Jaeger.
  • Loading branch information
shs96c committed Feb 22, 2021
1 parent a34ad83 commit 3a94ffb
Show file tree
Hide file tree
Showing 7 changed files with 426 additions and 363 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ java_library(
"//java/client/test/org/openqa/selenium/remote/tracing:__subpackages__",
],
deps = [
"//java:auto-service",
"//java/client/src/org/openqa/selenium:core",
"//java/client/src/org/openqa/selenium/json",
"//java/client/src/org/openqa/selenium/remote/tracing",
Expand All @@ -18,6 +19,7 @@ java_library(
artifact("io.opentelemetry:opentelemetry-exporter-logging"),
artifact("io.opentelemetry:opentelemetry-sdk"),
artifact("io.opentelemetry:opentelemetry-sdk-common"),
artifact("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure"),
artifact("io.opentelemetry:opentelemetry-sdk-trace"),
artifact("io.opentelemetry:opentelemetry-semconv"),
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,38 +17,15 @@

package org.openqa.selenium.remote.tracing.opentelemetry;

import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.trace.StatusCode;
import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.propagation.ContextPropagators;
import io.opentelemetry.context.propagation.TextMapPropagator;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.common.CompletableResultCode;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.trace.SdkTracerProvider;
import io.opentelemetry.sdk.trace.SpanProcessor;
import io.opentelemetry.sdk.trace.data.EventData;
import io.opentelemetry.sdk.trace.data.SpanData;
import io.opentelemetry.sdk.trace.data.StatusData;
import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor;
import io.opentelemetry.sdk.trace.export.SpanExporter;

import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
import io.opentelemetry.sdk.autoconfigure.OpenTelemetrySdkAutoConfiguration;
import org.openqa.selenium.internal.Require;
import org.openqa.selenium.json.Json;
import org.openqa.selenium.json.JsonOutput;
import org.openqa.selenium.remote.tracing.Propagator;
import org.openqa.selenium.remote.tracing.TraceContext;

import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.logging.Level;
import java.util.logging.Logger;

public class OpenTelemetryTracer implements org.openqa.selenium.remote.tracing.Tracer {
Expand Down Expand Up @@ -80,102 +57,22 @@ public static OpenTelemetryTracer getInstance() {

private static OpenTelemetryTracer createTracer() {
LOG.info("Using OpenTelemetry for tracing");
List<SpanProcessor> exporters = new LinkedList<>();
exporters.add(SimpleSpanProcessor.create(new SpanExporter() {
@Override
public CompletableResultCode export(Collection<SpanData> spans) {

spans.forEach(span -> {
LOG.fine(String.valueOf(span));

String traceId = span.getTraceId();
String spanId = span.getSpanId();
StatusData status = span.getStatus();
List<EventData> eventList = span.getEvents();
eventList.forEach(event -> {
Map<String, Object> map = new HashMap<>();
map.put("eventTime", event.getEpochNanos());
map.put("traceId", traceId);
map.put("spanId", spanId);
map.put("spanKind", span.getKind().toString());
map.put("eventName", event.getName());

Attributes attributes = event.getAttributes();
map.put("attributes", attributes.asMap());
String jsonString = getJsonString(map);
if (status.getStatusCode() == StatusCode.ERROR) {
LOG.log(Level.WARNING, jsonString);
} else {
LOG.log(Level.FINE, jsonString);
}
});
});
return CompletableResultCode.ofSuccess();
}

@Override
public CompletableResultCode flush() {
return CompletableResultCode.ofSuccess();
}

@Override
public CompletableResultCode shutdown() {
// no-op
return CompletableResultCode.ofSuccess();
}
}));

// The Jaeger exporter doesn't yet have a `TracerFactoryProvider`, so we
// shall look up the class using reflection, and beg for forgiveness
// later.
Optional<SpanExporter> maybeJaeger = JaegerTracing.findJaegerExporter();
maybeJaeger.ifPresent(
exporter -> exporters.add(SimpleSpanProcessor.create(exporter)));

Resource serviceNameResource =
Resource.create(Attributes.of(
ResourceAttributes.SERVICE_NAME,
System.getProperty("JAEGER_SERVICE_NAME", "selenium")));

// OpenTelemetry default propagators are no-op since version 0.9.0.
// Hence, required propagators need to defined and added.
ContextPropagators propagators =
ContextPropagators.create((W3CTraceContextPropagator.getInstance()));

SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder()
.addSpanProcessor(SpanProcessor.composite(exporters))
.setResource(Resource.getDefault().merge(serviceNameResource))
.build();

OpenTelemetrySdk openTelemetrySdk = OpenTelemetrySdk.builder()
.setTracerProvider(sdkTracerProvider)
.setPropagators(propagators)
.buildAndRegisterGlobal();

Runtime.getRuntime()
.addShutdownHook(new Thread(sdkTracerProvider::close));
OpenTelemetrySdk autoConfiguredSdk = OpenTelemetrySdkAutoConfiguration.initialize();

return new OpenTelemetryTracer(
openTelemetrySdk.getTracer("default"),
propagators.getTextMapPropagator());
}

private static String getJsonString(Map<String, Object> map) {
StringBuilder text = new StringBuilder();
try (JsonOutput json = new Json().newOutput(text).setPrettyPrint(false)) {
json.write(map);
text.append('\n');
}
return text.toString();
autoConfiguredSdk.getTracer("default"),
autoConfiguredSdk.getPropagators().getTextMapPropagator());
}

private final Tracer tracer;
private final OpenTelemetryPropagator telemetryPropagator;

public OpenTelemetryTracer(Tracer tracer, TextMapPropagator textMapPropagator) {
public OpenTelemetryTracer(Tracer tracer, TextMapPropagator propagator) {
this.tracer = Require.nonNull("Tracer", tracer);
this.telemetryPropagator = new OpenTelemetryPropagator(
tracer, Require.nonNull("Formatter", textMapPropagator));
tracer,
Require.nonNull("Formatter", propagator));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you 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 org.openqa.selenium.remote.tracing.opentelemetry;

import com.google.auto.service.AutoService;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.trace.StatusCode;
import io.opentelemetry.sdk.autoconfigure.spi.SdkTracerProviderConfigurer;
import io.opentelemetry.sdk.common.CompletableResultCode;
import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder;
import io.opentelemetry.sdk.trace.data.EventData;
import io.opentelemetry.sdk.trace.data.SpanData;
import io.opentelemetry.sdk.trace.data.StatusData;
import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor;
import io.opentelemetry.sdk.trace.export.SpanExporter;
import org.openqa.selenium.json.Json;
import org.openqa.selenium.json.JsonOutput;

import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

@AutoService(SdkTracerProviderConfigurer.class)
public class SeleniumSpanExporter implements SdkTracerProviderConfigurer {
private static final Logger LOG = Logger.getLogger(SeleniumSpanExporter.class.getName());

@Override
public void configure(SdkTracerProviderBuilder tracerProvider) {
tracerProvider.addSpanProcessor(SimpleSpanProcessor.create(new SpanExporter() {
@Override
public CompletableResultCode export(Collection<SpanData> spans) {
spans.forEach(span -> {
LOG.fine(String.valueOf(span));

String traceId = span.getTraceId();
String spanId = span.getSpanId();
StatusData status = span.getStatus();
List<EventData> eventList = span.getEvents();
eventList.forEach(event -> {
Map<String, Object> map = new HashMap<>();
map.put("eventTime", event.getEpochNanos());
map.put("traceId", traceId);
map.put("spanId", spanId);
map.put("spanKind", span.getKind().toString());
map.put("eventName", event.getName());

Attributes attributes = event.getAttributes();
map.put("attributes", attributes.asMap());
String jsonString = getJsonString(map);
if (status.getStatusCode() == StatusCode.ERROR) {
LOG.log(Level.WARNING, jsonString);
} else {
LOG.log(Level.FINE, jsonString);
}
});
});
return CompletableResultCode.ofSuccess();
}

@Override
public CompletableResultCode flush() {
return CompletableResultCode.ofSuccess();
}

@Override
public CompletableResultCode shutdown() {
// no-op
return CompletableResultCode.ofSuccess();
}
}));
}

private static String getJsonString(Map<String, Object> map) {
StringBuilder text = new StringBuilder();
try (JsonOutput json = new Json().newOutput(text).setPrettyPrint(false)) {
json.write(map);
text.append('\n');
}
return text.toString();
}
}
1 change: 1 addition & 0 deletions java/maven_deps.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ def selenium_java_deps():
"io.opentelemetry:opentelemetry-semconv:%s" % opentelemetry_version+"-alpha",
"io.opentelemetry:opentelemetry-sdk:%s" % opentelemetry_version,
"io.opentelemetry:opentelemetry-sdk-common:%s" % opentelemetry_version,
"io.opentelemetry:opentelemetry-sdk-extension-autoconfigure:0.16.0-alpha",
"io.opentelemetry:opentelemetry-sdk-testing:%s" % opentelemetry_version,
"io.opentelemetry:opentelemetry-sdk-trace:%s" % opentelemetry_version,
"io.ous:jtoml:2.0.0",
Expand Down
Loading

0 comments on commit 3a94ffb

Please sign in to comment.