Skip to content

Commit a449eca

Browse files
committed
[tracing] Initial implementation
1 parent 4813c06 commit a449eca

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+760
-256
lines changed

java/client/src/org/openqa/selenium/remote/tracing/HttpTracing.java

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,12 @@
2121
import io.opentracing.SpanContext;
2222
import io.opentracing.Tracer;
2323
import io.opentracing.propagation.Format;
24+
import io.opentracing.propagation.TextMap;
2425
import io.opentracing.propagation.TextMapAdapter;
2526
import io.opentracing.tag.Tags;
2627
import org.openqa.selenium.remote.http.HttpRequest;
2728

28-
import java.util.Collections;
29+
import java.util.Iterator;
2930
import java.util.LinkedHashMap;
3031
import java.util.Map;
3132
import java.util.Objects;
@@ -37,25 +38,45 @@ private HttpTracing() {
3738
}
3839

3940
public static SpanContext extract(Tracer tracer, HttpRequest request) {
41+
Objects.requireNonNull(tracer, "Tracer to use must be set.");
42+
Objects.requireNonNull(request, "Request must be set.");
43+
4044
return tracer.extract(Format.Builtin.HTTP_HEADERS, new HttpRequestAdapter(request));
4145
}
4246

4347
public static void inject(Tracer tracer, Span span, HttpRequest request) {
44-
Objects.requireNonNull(request, "Request must be set.");
4548
if (span == null) {
49+
// Do nothing.
4650
return;
4751
}
4852

53+
Objects.requireNonNull(tracer, "Tracer to use must be set.");
54+
Objects.requireNonNull(request, "Request must be set.");
55+
4956
span.setTag(Tags.HTTP_METHOD.getKey(), request.getMethod().toString());
5057
span.setTag(Tags.HTTP_URL.getKey(), request.getUri());
5158

5259
tracer.inject(span.context(), Format.Builtin.HTTP_HEADERS, new HttpRequestAdapter(request));
5360
}
5461

55-
private static class HttpRequestAdapter extends TextMapAdapter {
62+
private static class HttpRequestAdapter implements TextMap {
63+
64+
private final HttpRequest request;
5665

5766
public HttpRequestAdapter(HttpRequest request) {
58-
super(asMap(request));
67+
this.request = Objects.requireNonNull(request, "Request to use must be set.");
68+
}
69+
70+
@Override
71+
public void put(String key, String value) {
72+
Objects.requireNonNull(key, "Key to use must be set.");
73+
Objects.requireNonNull(value, "Value to use must be set.");
74+
request.setHeader(key, value);
75+
}
76+
77+
@Override
78+
public Iterator<Map.Entry<String, String>> iterator() {
79+
return asMap(request).entrySet().iterator();
5980
}
6081

6182
private static Map<String, String> asMap(HttpRequest request) {
@@ -67,12 +88,7 @@ private static Map<String, String> asMap(HttpRequest request) {
6788
}
6889
})
6990
);
70-
return Collections.unmodifiableMap(entries);
71-
}
72-
73-
@Override
74-
public void put(String key, String value) {
75-
super.put(key, value);
91+
return entries;
7692
}
7793
}
7894
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package org.openqa.selenium.remote.tracing;
2+
3+
import io.opentracing.Tracer;
4+
import org.openqa.selenium.remote.http.Filter;
5+
import org.openqa.selenium.remote.http.HttpHandler;
6+
import org.openqa.selenium.remote.http.HttpRequest;
7+
8+
import java.util.Objects;
9+
import java.util.function.Function;
10+
11+
public class SpanDecorator implements Filter {
12+
13+
private final Tracer tracer;
14+
private final Function<HttpRequest, String> namer;
15+
16+
public SpanDecorator(Tracer tracer, Function<HttpRequest, String> namer) {
17+
this.tracer = Objects.requireNonNull(tracer, "Tracer to use must be set.");
18+
this.namer = Objects.requireNonNull(namer, "Naming function must be set.");
19+
}
20+
21+
@Override
22+
public HttpHandler apply(HttpHandler handler) {
23+
return new SpanWrappedHttpHandler(tracer, namer, handler);
24+
}
25+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package org.openqa.selenium.remote.tracing;
2+
3+
import io.opentracing.Span;
4+
import io.opentracing.SpanContext;
5+
import io.opentracing.Tracer;
6+
import io.opentracing.tag.Tags;
7+
import org.openqa.selenium.remote.http.HttpHandler;
8+
import org.openqa.selenium.remote.http.HttpRequest;
9+
import org.openqa.selenium.remote.http.HttpResponse;
10+
11+
import java.io.UncheckedIOException;
12+
import java.util.Objects;
13+
import java.util.function.Function;
14+
import java.util.logging.Logger;
15+
16+
public class SpanWrappedHttpHandler implements HttpHandler {
17+
18+
private static final Logger LOG = Logger.getLogger(SpanWrappedHttpHandler.class.getName());
19+
private final Tracer tracer;
20+
private final Function<HttpRequest, String> namer;
21+
private final HttpHandler delegate;
22+
23+
public SpanWrappedHttpHandler(Tracer tracer, Function<HttpRequest, String> namer, HttpHandler delegate) {
24+
this.tracer = Objects.requireNonNull(tracer, "Tracer to use must be set.");
25+
this.namer = Objects.requireNonNull(namer, "Naming function must be set.");
26+
this.delegate = Objects.requireNonNull(delegate, "Actual handler must be set.");
27+
}
28+
29+
@Override
30+
public HttpResponse execute(HttpRequest req) throws UncheckedIOException {
31+
String name = Objects.requireNonNull(namer.apply(req), "Operation name must be set for " + req);
32+
33+
Span previousSpan = tracer.scopeManager().activeSpan();
34+
SpanContext context = HttpTracing.extract(tracer, req);
35+
Span span = tracer.buildSpan(name).asChildOf(context).ignoreActiveSpan().start();
36+
tracer.scopeManager().activate(span);
37+
38+
try {
39+
span.setTag(Tags.SPAN_KIND, Tags.SPAN_KIND_SERVER)
40+
.setTag(Tags.HTTP_METHOD, req.getMethod().toString())
41+
.setTag(Tags.HTTP_URL, req.getUri());
42+
HttpTracing.inject(tracer, span, req);
43+
44+
HttpResponse res = delegate.execute(req);
45+
46+
span.setTag(Tags.HTTP_STATUS, res.getStatus());
47+
48+
return res;
49+
} catch (Throwable t) {
50+
span.setTag(Tags.ERROR, true);
51+
throw t;
52+
} finally {
53+
span.finish();
54+
tracer.scopeManager().activate(previousSpan);
55+
}
56+
}
57+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package org.openqa.selenium.remote.tracing;
2+
3+
import io.opentracing.Tracer;
4+
import org.openqa.selenium.remote.http.HttpRequest;
5+
import org.openqa.selenium.remote.http.Routable;
6+
7+
import java.util.Objects;
8+
import java.util.function.Function;
9+
10+
public class SpanWrappedRoutable extends SpanWrappedHttpHandler implements Routable {
11+
private final Routable delegate;
12+
13+
public SpanWrappedRoutable(Tracer tracer, Function<HttpRequest, String> namer, Routable delegate) {
14+
super(tracer, namer, delegate);
15+
16+
this.delegate = Objects.requireNonNull(delegate, "Routable to use must be set.");
17+
}
18+
19+
@Override
20+
public boolean matches(HttpRequest req) {
21+
return delegate.matches(req);
22+
}
23+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package org.openqa.selenium.remote.tracing;
2+
3+
import io.opentracing.Span;
4+
import io.opentracing.Tracer;
5+
6+
import java.util.concurrent.Callable;
7+
8+
public class TracedCallable<T> implements Callable<T> {
9+
10+
private final Tracer tracer;
11+
private final Span span;
12+
private final Callable<T> delegate;
13+
14+
public TracedCallable(Tracer tracer, Span span, Callable<T> delegate) {
15+
this.tracer = tracer;
16+
this.span = span;
17+
this.delegate = delegate;
18+
}
19+
20+
@Override
21+
public T call() throws Exception {
22+
Span previousSpan = tracer.scopeManager().activeSpan();
23+
tracer.scopeManager().activate(this.span);
24+
try {
25+
return delegate.call();
26+
} finally {
27+
tracer.scopeManager().activate(previousSpan);
28+
}
29+
}
30+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package org.openqa.selenium.remote.tracing;
2+
3+
import io.opentracing.Tracer;
4+
import org.openqa.selenium.remote.http.ClientConfig;
5+
import org.openqa.selenium.remote.http.HttpClient;
6+
import org.openqa.selenium.remote.http.HttpRequest;
7+
import org.openqa.selenium.remote.http.HttpResponse;
8+
import org.openqa.selenium.remote.http.WebSocket;
9+
10+
import java.io.UncheckedIOException;
11+
import java.net.URL;
12+
import java.util.Objects;
13+
14+
public class TracedHttpClient implements HttpClient {
15+
16+
private final Tracer tracer;
17+
private final HttpClient delegate;
18+
19+
private TracedHttpClient(Tracer tracer, HttpClient delegate) {
20+
this.tracer = Objects.requireNonNull(tracer);
21+
this.delegate = Objects.requireNonNull(delegate);
22+
}
23+
24+
@Override
25+
public WebSocket openSocket(HttpRequest request, WebSocket.Listener listener) {
26+
return delegate.openSocket(request, listener);
27+
}
28+
29+
@Override
30+
public HttpResponse execute(HttpRequest req) throws UncheckedIOException {
31+
return delegate.execute(req);
32+
}
33+
34+
public static class Factory implements HttpClient.Factory {
35+
36+
private final Tracer tracer;
37+
private final HttpClient.Factory delegate;
38+
39+
public Factory(Tracer tracer, HttpClient.Factory delegate) {
40+
this.tracer = Objects.requireNonNull(tracer);
41+
this.delegate = Objects.requireNonNull(delegate);
42+
}
43+
44+
public HttpClient createClient(ClientConfig config) {
45+
HttpClient client = delegate.createClient(config);
46+
return new TracedHttpClient(tracer, client);
47+
}
48+
49+
@Override
50+
public HttpClient createClient(URL url) {
51+
HttpClient client = delegate.createClient(url);
52+
return new TracedHttpClient(tracer, client);
53+
}
54+
}
55+
56+
}

java/server/src/com/thoughtworks/selenium/webdriven/WebDriverBackedSeleniumHandler.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import com.google.common.base.Splitter;
2222
import com.thoughtworks.selenium.CommandProcessor;
2323
import com.thoughtworks.selenium.SeleniumException;
24+
import io.opentracing.Tracer;
2425
import org.openqa.selenium.Capabilities;
2526
import org.openqa.selenium.ImmutableCapabilities;
2627
import org.openqa.selenium.chrome.ChromeOptions;
@@ -70,7 +71,7 @@ public class WebDriverBackedSeleniumHandler implements Routable {
7071
private ActiveSessions sessions;
7172
private ActiveSessionListener listener;
7273

73-
public WebDriverBackedSeleniumHandler(ActiveSessions sessions) {
74+
public WebDriverBackedSeleniumHandler(Tracer tracer, ActiveSessions sessions) {
7475
this.sessions = sessions == null ? new ActiveSessions(5, MINUTES) : sessions;
7576
listener = new ActiveSessionListener() {
7677
@Override
@@ -80,7 +81,7 @@ public void onStop(ActiveSession session) {
8081
};
8182
sessions.addListener(listener);
8283

83-
this.pipeline = NewSessionPipeline.builder().add(new ActiveSessionFactory()).create();
84+
this.pipeline = NewSessionPipeline.builder().add(new ActiveSessionFactory(tracer)).create();
8485
}
8586

8687
@Override

java/server/src/org/openqa/selenium/grid/commands/Hub.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import com.beust.jcommander.JCommander;
2121
import com.beust.jcommander.ParameterException;
2222
import com.google.auto.service.AutoService;
23+
import io.opentracing.Tracer;
2324
import org.openqa.selenium.BuildInfo;
2425
import org.openqa.selenium.cli.CliCommand;
2526
import org.openqa.selenium.events.EventBus;
@@ -98,6 +99,7 @@ public Executable configure(String... args) {
9899

99100
LoggingOptions loggingOptions = new LoggingOptions(config);
100101
loggingOptions.configureLogging();
102+
Tracer tracer = loggingOptions.getTracer();
101103

102104
EventBusConfig events = new EventBusConfig(config);
103105
EventBus bus = events.getEventBus();
@@ -115,11 +117,12 @@ public Executable configure(String... args) {
115117
HttpClient.Factory.createDefault());
116118

117119
Distributor distributor = new LocalDistributor(
120+
tracer,
118121
bus,
119122
clientFactory,
120123
sessions);
121124
handler.addHandler(distributor);
122-
Router router = new Router(clientFactory, sessions, distributor);
125+
Router router = new Router(tracer, clientFactory, sessions, distributor);
123126

124127
Server<?> server = new NettyServer(serverOptions, router);
125128
server.start();

java/server/src/org/openqa/selenium/grid/commands/Standalone.java

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import com.beust.jcommander.JCommander;
2121
import com.beust.jcommander.ParameterException;
2222
import com.google.auto.service.AutoService;
23+
import io.opentracing.Tracer;
2324
import org.openqa.selenium.BuildInfo;
2425
import org.openqa.selenium.WebDriverException;
2526
import org.openqa.selenium.cli.CliCommand;
@@ -51,6 +52,7 @@
5152
import org.openqa.selenium.net.NetworkUtils;
5253
import org.openqa.selenium.netty.server.NettyServer;
5354
import org.openqa.selenium.remote.http.HttpClient;
55+
import org.openqa.selenium.remote.tracing.TracedHttpClient;
5456

5557
import java.net.URI;
5658
import java.net.URISyntaxException;
@@ -113,6 +115,7 @@ public Executable configure(String... args) {
113115

114116
LoggingOptions loggingOptions = new LoggingOptions(config);
115117
loggingOptions.configureLogging();
118+
Tracer tracer = loggingOptions.getTracer();
116119

117120
EventBusConfig events = new EventBusConfig(config);
118121
EventBus bus = events.getEventBus();
@@ -134,25 +137,28 @@ public Executable configure(String... args) {
134137
}
135138

136139
CombinedHandler combinedHandler = new CombinedHandler();
137-
HttpClient.Factory clientFactory = new RoutableHttpClientFactory(
138-
localhost.toURL(),
139-
combinedHandler,
140-
HttpClient.Factory.createDefault());
140+
HttpClient.Factory clientFactory = new TracedHttpClient.Factory(
141+
tracer,
142+
new RoutableHttpClientFactory(
143+
localhost.toURL(),
144+
combinedHandler,
145+
HttpClient.Factory.createDefault()));
141146

142147
SessionMap sessions = new LocalSessionMap(bus);
143148
combinedHandler.addHandler(sessions);
144-
Distributor distributor = new LocalDistributor(bus, clientFactory, sessions);
149+
Distributor distributor = new LocalDistributor(tracer, bus, clientFactory, sessions);
145150
combinedHandler.addHandler(distributor);
146-
Router router = new Router(clientFactory, sessions, distributor);
151+
Router router = new Router(tracer, clientFactory, sessions, distributor);
147152

148153
LocalNode.Builder nodeBuilder = LocalNode.builder(
154+
tracer,
149155
bus,
150156
clientFactory,
151157
localhost)
152158
.maximumConcurrentSessions(Runtime.getRuntime().availableProcessors() * 3);
153159

154-
new NodeOptions(config).configure(clientFactory, nodeBuilder);
155-
new DockerOptions(config).configure(clientFactory, nodeBuilder);
160+
new NodeOptions(config).configure(tracer, clientFactory, nodeBuilder);
161+
new DockerOptions(config).configure(tracer, clientFactory, nodeBuilder);
156162

157163
Node node = nodeBuilder.build();
158164
combinedHandler.addHandler(node);

0 commit comments

Comments
 (0)