Skip to content

Commit

Permalink
Provide our own APIs for tracing
Browse files Browse the repository at this point in the history
  • Loading branch information
shs96c committed May 6, 2020
1 parent 0570e9d commit 1f9c963
Show file tree
Hide file tree
Showing 92 changed files with 1,363 additions and 347 deletions.
4 changes: 2 additions & 2 deletions java/client/src/org/openqa/selenium/remote/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ java_export(
"org.openqa.selenium.remote.internal",
],
uses = [
"io.opentelemetry.trace.Tracer",
"org.openqa.selenium.remote.session.CapabilitiesFilter",
"org.openqa.selenium.remote.session.CapabilityTransform",
"org.openqa.selenium.remote.service.DriverService$Builder",
Expand All @@ -82,6 +81,7 @@ java_export(
"//java/client/src/org/openqa/selenium/os",
"//java/client/src/org/openqa/selenium/remote/http",
"//java/client/src/org/openqa/selenium/remote/tracing",
"//java/client/src/org/openqa/selenium/remote/tracing/opentelemetry",
],
deps = [
":api",
Expand All @@ -92,8 +92,8 @@ java_export(
"//java/client/src/org/openqa/selenium/os",
"//java/client/src/org/openqa/selenium/remote/http/netty",
"//java/client/src/org/openqa/selenium/remote/http/okhttp",
"//java/client/src/org/openqa/selenium/remote/tracing",
artifact("com.google.guava:guava"),
artifact("io.opentelemetry:opentelemetry-api"),
artifact("net.bytebuddy:byte-buddy"),
],
)
Expand Down
2 changes: 1 addition & 1 deletion java/client/src/org/openqa/selenium/remote/RemoteTags.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@

package org.openqa.selenium.remote;

import io.opentelemetry.trace.Span;
import org.openqa.selenium.Capabilities;
import org.openqa.selenium.remote.tracing.Span;

import java.util.function.BiConsumer;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
import java.util.function.Supplier;
import java.util.stream.Collectors;

class HttpMessage<M extends HttpMessage<M>> {
abstract class HttpMessage<M extends HttpMessage<M>> {

private final Multimap<String, String> headers = ArrayListMultimap.create();
private final Map<String, Object> attributes = new HashMap<>();
Expand Down
15 changes: 12 additions & 3 deletions java/client/src/org/openqa/selenium/remote/tracing/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,25 @@ load("@rules_jvm_external//:defs.bzl", "artifact")

java_library(
name = "tracing",
srcs = glob(["*.java"]),
exports = [
":tracing-lib",
],
visibility = [
"//java/client/src/org/openqa/selenium/remote:__pkg__",
"//java/client/src/org/openqa/selenium/remote/tracing:__subpackages__",
"//java/client/test/org/openqa/selenium/remote/tracing:__subpackages__",
],
)

java_library(
name = "tracing-lib",
srcs = glob(["*.java"]),
exports = [
# Exposed by tracing APIs
"//java/client/src/org/openqa/selenium/remote/http",
artifact("io.opentelemetry:opentelemetry-api"),
artifact("io.opentelemetry:opentelemetry-context-prop"),
],
visibility = [
"//java/client/src/org/openqa/selenium/remote/tracing/empty:__pkg__",
],
deps = [
"//java/client/src/org/openqa/selenium/remote/http",
Expand Down
52 changes: 10 additions & 42 deletions java/client/src/org/openqa/selenium/remote/tracing/HttpTracing.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,6 @@

package org.openqa.selenium.remote.tracing;

import io.opentelemetry.trace.Span;
import io.opentelemetry.trace.SpanContext;
import io.opentelemetry.trace.SpanId;
import io.opentelemetry.trace.TraceFlags;
import io.opentelemetry.trace.TraceId;
import io.opentelemetry.trace.TraceState;
import io.opentelemetry.trace.Tracer;
import org.openqa.selenium.remote.http.HttpRequest;

import java.util.Objects;
Expand All @@ -32,53 +25,30 @@
public class HttpTracing {

private static final Logger LOG = Logger.getLogger(HttpTracing.class.getName());
private static final SpanContext NO_OP_CONTEXT = SpanContext.create(
TraceId.getInvalid(),
SpanId.getInvalid(),
TraceFlags.getDefault(),
TraceState.getDefault());

private HttpTracing() {
// Utility classes
}

private static SpanContext extract(Tracer tracer, HttpRequest request) {
private static TraceContext extract(Tracer tracer, HttpRequest request) {
Objects.requireNonNull(tracer, "Tracer to use must be set.");
Objects.requireNonNull(request, "Request must be set.");

try {
return tracer.getHttpTextFormat().extract(request, (req, key) -> req.getHeader(key));
} catch (IllegalArgumentException ignored) {
// See: https://github.com/open-telemetry/opentelemetry-java/issues/767
// Fall through
}
return NO_OP_CONTEXT;
return tracer.getPropagator().extractContext(tracer.getCurrentContext(), request, (req, key) -> req.getHeader(key));
}

public static Span.Builder newSpanAsChildOf(Tracer tracer, HttpRequest request, String name) {
public static Span newSpanAsChildOf(Tracer tracer, HttpRequest request, String name) {
Objects.requireNonNull(tracer, "Tracer to use must be set.");
Objects.requireNonNull(request, "Request must be set.");
Objects.requireNonNull(name, "Name to use must be set.");

SpanContext parent = extract(tracer, request);

Span.Builder builder = tracer.spanBuilder(name);
if (parent != null) {
if (parent.equals(NO_OP_CONTEXT) && tracer.getCurrentSpan() != null) {
builder.setParent(tracer.getCurrentSpan());
} else {
builder.setParent(parent);
}
} else {
// This should never happen, but you never know, right?
builder.setNoParent();
}

return builder;
TraceContext parent = extract(tracer, request);
System.out.println(parent);
return parent.createSpan(name);
}

public static void inject(Tracer tracer, Span span, HttpRequest request) {
if (span == null) {
public static void inject(Tracer tracer, TraceContext context, HttpRequest request) {
if (context == null) {
// Do nothing.
return;
}
Expand All @@ -87,10 +57,8 @@ public static void inject(Tracer tracer, Span span, HttpRequest request) {
Objects.requireNonNull(request, "Request must be set.");

StackTraceElement caller = Thread.currentThread().getStackTrace()[2];
LOG.fine(String.format("Injecting %s into %s at %s:%d", request, span, caller.getClassName(), caller.getLineNumber()));
LOG.fine(String.format("Injecting %s into %s at %s:%d", request, context, caller.getClassName(), caller.getLineNumber()));

span.setAttribute("http.method", request.getMethod().toString());
span.setAttribute("http.url", request.getUri());
tracer.getHttpTextFormat().inject(span.getContext(), request, (req, key, value) -> req.setHeader(key, value));
tracer.getPropagator().inject(context, request, (req, key, value) -> req.setHeader(key, value));
}
}
31 changes: 31 additions & 0 deletions java/client/src/org/openqa/selenium/remote/tracing/Propagator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// 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;

import java.util.function.BiFunction;

public interface Propagator {

<C> void inject(TraceContext toInject, C carrier, Setter<C> setter);

<C> TraceContext extractContext(TraceContext existing, C carrier, BiFunction<C, String, String> getter);

interface Setter<C> {
void set(C carrier, String key, String value);
}
}
53 changes: 53 additions & 0 deletions java/client/src/org/openqa/selenium/remote/tracing/Span.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// 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;

public interface Span extends AutoCloseable, TraceContext {

Span setName(String name);

Span setAttribute(String key, boolean value);
Span setAttribute(String key, Number value);
Span setAttribute(String key, String value);

Span setStatus(Status status);

@Override
void close();

enum Kind {
CLIENT("client"),
SERVER("server"),

PRODUCER("producer"),
CONSUMER("consumer"),
;

// The nice name is the name expected in an OT trace.
private final String niceName;

private Kind(String niceName) {
this.niceName = niceName;
}

@Override
public String toString() {
return niceName;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@

package org.openqa.selenium.remote.tracing;

import io.opentelemetry.trace.Tracer;
import org.openqa.selenium.remote.http.Filter;
import org.openqa.selenium.remote.http.HttpHandler;
import org.openqa.selenium.remote.http.HttpRequest;
Expand Down
48 changes: 48 additions & 0 deletions java/client/src/org/openqa/selenium/remote/tracing/SpanId.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// 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;

import java.util.Objects;

public class SpanId {

private final Object underlyingId;

public SpanId(Object underlyingId) {
this.underlyingId = Objects.requireNonNull(underlyingId);
}

@Override
public String toString() {
return underlyingId.toString();
}

@Override
public boolean equals(Object o) {
if (!(o instanceof SpanId)) {
return false;
}
SpanId that = (SpanId) o;
return Objects.equals(this.underlyingId, that.underlyingId);
}

@Override
public int hashCode() {
return Objects.hash(underlyingId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,21 @@

package org.openqa.selenium.remote.tracing;

import io.opentelemetry.context.Scope;
import io.opentelemetry.trace.Span;
import io.opentelemetry.trace.Status;
import io.opentelemetry.trace.Tracer;
import org.openqa.selenium.remote.http.HttpHandler;
import org.openqa.selenium.remote.http.HttpRequest;
import org.openqa.selenium.remote.http.HttpResponse;

import java.io.UncheckedIOException;
import java.util.Objects;
import java.util.UUID;
import java.util.function.Function;
import java.util.logging.Level;
import java.util.logging.Logger;

import static io.opentelemetry.trace.Span.Kind.SERVER;
import static org.openqa.selenium.remote.tracing.HttpTags.HTTP_REQUEST;
import static org.openqa.selenium.remote.tracing.HttpTags.HTTP_RESPONSE;
import static org.openqa.selenium.remote.tracing.HttpTracing.newSpanAsChildOf;
import static org.openqa.selenium.remote.tracing.Tags.HTTP_REQUEST;
import static org.openqa.selenium.remote.tracing.Tags.HTTP_RESPONSE;
import static org.openqa.selenium.remote.tracing.Tags.KIND;

public class SpanWrappedHttpHandler implements HttpHandler {

Expand All @@ -51,11 +48,27 @@ public SpanWrappedHttpHandler(Tracer tracer, Function<HttpRequest, String> namer

@Override
public HttpResponse execute(HttpRequest req) throws UncheckedIOException {
// If there is already a span attached to this request, then do nothing.
Object possibleSpan = req.getAttribute("selenium.tracing.span");
if (possibleSpan instanceof Span) {
return delegate.execute(req);
}

String name = Objects.requireNonNull(namer.apply(req), "Operation name must be set for " + req);

Span span = newSpanAsChildOf(tracer, req, name).setSpanKind(SERVER).startSpan();
TraceContext before = tracer.getCurrentContext();
Span span = newSpanAsChildOf(tracer, req, name);
try {
TraceContext after = tracer.getCurrentContext();
span.setAttribute("random.key", UUID.randomUUID().toString());

req.setAttribute("selenium.tracing.span", span);

if (!(after.getClass().getName().equals("org.openqa.selenium.remote.tracing.empty.NullContext"))) {
LOG.info(String.format("Wrapping request. Before %s and after %s", before, after));
}

try (Scope scope = tracer.withSpan(span)) {
KIND.accept(span, Span.Kind.SERVER);
HTTP_REQUEST.accept(span, req);
HttpTracing.inject(tracer, span, req);

Expand All @@ -70,7 +83,7 @@ public HttpResponse execute(HttpRequest req) throws UncheckedIOException {
LOG.log(Level.WARNING, "Unable to execute request: " + t.getMessage(), t);
throw t;
} finally {
span.end();
span.close();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@

package org.openqa.selenium.remote.tracing;

import io.opentelemetry.trace.Tracer;
import org.openqa.selenium.remote.http.HttpRequest;
import org.openqa.selenium.remote.http.Routable;

Expand Down
Loading

0 comments on commit 1f9c963

Please sign in to comment.