Skip to content

Commit

Permalink
Wire tracing into the node
Browse files Browse the repository at this point in the history
  • Loading branch information
shs96c committed Nov 10, 2018
1 parent c7c9ecb commit 570f533
Show file tree
Hide file tree
Showing 14 changed files with 148 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ public Span createChild(String operation) {
return child.activate();
}

@Override
public Span setName(String name) {
allSpans.forEach(span -> span.setName(name));
return this;
}

@Override
public Span addTraceTag(String key, String value) {
Objects.requireNonNull(key, "Key must be set");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public static DistributedTracer getInstance() {
return INSTANCE;
}

public synchronized void setInstance(DistributedTracer distributedTracer) {
public synchronized static void setInstance(DistributedTracer distributedTracer) {
INSTANCE = distributedTracer;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,15 @@ public Span activate() {
return this;
}

@Override
public Span setName(String name) {
Objects.requireNonNull(name, "Name must be set.");

// TODO: Actually change the name of the span

return this;
}

@Override
public Span addTraceTag(String key, String value) {
span.putAttribute(Objects.requireNonNull(key), AttributeValue.stringAttributeValue(value));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,13 @@ public Span activate() {
return this;
}

@Override
public Span setName(String name) {
Objects.requireNonNull(name, "Name must be set.");
span.setOperationName(name);
return this;
}

@Override
public Span addTraceTag(String key, String value) {
span.setBaggageItem(Objects.requireNonNull(key), value);
Expand Down
2 changes: 2 additions & 0 deletions java/client/src/org/openqa/selenium/remote/tracing/Span.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ public abstract class Span implements Closeable {
*/
public abstract Span activate();

public abstract Span setName(String name);

/**
* Add a tag that will be transmitted across the wire to allow remote traces
* to also have the value. This is equivalent to OpenTracing's concept of
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,15 +114,15 @@ public Executable configure(String... args) {
throw new RuntimeException(e);
}

LocalNode.Builder node = LocalNode.builder(localhost, sessions)
DistributedTracer tracer = DistributedTracer.getInstance();

LocalNode.Builder node = LocalNode.builder(tracer, localhost, sessions)
.maximumConcurrentSessions(Runtime.getRuntime().availableProcessors() * 3);
nodeFlags.configure(node);

distributor.add(node.build());

Server<?> server = new BaseServer<>(
DistributedTracer.getInstance(),
new BaseServerOptions(config));
Server<?> server = new BaseServer<>(tracer, new BaseServerOptions(config));
server.addRoute(Routes.matching(router).using(router).decorateWith(W3CCommandHandler.class));
server.start();
};
Expand Down
18 changes: 15 additions & 3 deletions java/server/src/org/openqa/selenium/grid/distributor/AddNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.openqa.selenium.remote.http.HttpClient;
import org.openqa.selenium.remote.http.HttpRequest;
import org.openqa.selenium.remote.http.HttpResponse;
import org.openqa.selenium.remote.tracing.DistributedTracer;

import java.io.IOException;
import java.net.URI;
Expand All @@ -42,11 +43,17 @@

public class AddNode implements CommandHandler {

private final DistributedTracer tracer;
private final Distributor distributor;
private final Json json;
private final HttpClient.Factory httpFactory;

public AddNode(Distributor distributor, Json json, HttpClient.Factory httpFactory) {
public AddNode(
DistributedTracer tracer,
Distributor distributor,
Json json,
HttpClient.Factory httpFactory) {
this.tracer = Objects.requireNonNull(tracer);
this.distributor = Objects.requireNonNull(distributor);
this.json = Objects.requireNonNull(json);
this.httpFactory = Objects.requireNonNull(httpFactory);
Expand All @@ -57,7 +64,7 @@ public void execute(HttpRequest req, HttpResponse resp) throws IOException {
Map<String, Object> raw = json.toType(req.getContentString(), MAP_TYPE);

UUID id = UUID.fromString((String) raw.get("id"));
URI uri = null;
URI uri;
try {
uri = new URI((String) raw.get("uri"));
} catch (URISyntaxException e) {
Expand All @@ -71,7 +78,12 @@ public void execute(HttpRequest req, HttpResponse resp) throws IOException {
.map(ImmutableCapabilities::new)
.collect(Collectors.toList());

Node node = new RemoteNode(id, uri, capabilities, httpFactory.createClient(uri.toURL()));
Node node = new RemoteNode(
tracer,
id,
uri,
capabilities,
httpFactory.createClient(uri.toURL()));

distributor.add(node);
}
Expand Down
12 changes: 11 additions & 1 deletion java/server/src/org/openqa/selenium/grid/node/Node.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
import org.openqa.selenium.remote.SessionId;
import org.openqa.selenium.remote.http.HttpRequest;
import org.openqa.selenium.remote.http.HttpResponse;
import org.openqa.selenium.remote.tracing.DistributedTracer;
import org.openqa.selenium.remote.tracing.Span;

import java.io.IOException;
import java.util.Objects;
Expand Down Expand Up @@ -90,17 +92,20 @@
*/
public abstract class Node implements Predicate<HttpRequest>, CommandHandler {

private final DistributedTracer tracer;
private final UUID id;
private final Injector injector;
private final Routes routes;

protected Node(UUID id) {
protected Node(DistributedTracer tracer, UUID id) {
this.tracer = Objects.requireNonNull(tracer);
this.id = Objects.requireNonNull(id);

Json json = new Json();
injector = Injector.builder()
.register(this)
.register(json)
.register(tracer)
.build();

routes = combine(
Expand Down Expand Up @@ -156,4 +161,9 @@ public void execute(HttpRequest req, HttpResponse resp) throws IOException {
}
handler.get().execute(req, resp);
}

protected Span createSpan(String operationName) {
Objects.requireNonNull(operationName);
return tracer.createSpan(operationName, tracer.getActiveSpan());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,10 @@ public Executable configure(String... args) {

BaseServerOptions serverOptions = new BaseServerOptions(config);

LocalNode.Builder builder = LocalNode.builder(serverOptions.getExternalUri(), sessions);
LocalNode.Builder builder = LocalNode.builder(
DistributedTracer.getInstance(),
serverOptions.getExternalUri(),
sessions);
nodeFlags.configure(builder);
LocalNode node = builder.build();

Expand Down
108 changes: 63 additions & 45 deletions java/server/src/org/openqa/selenium/grid/node/local/LocalNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
import org.openqa.selenium.remote.SessionId;
import org.openqa.selenium.remote.http.HttpRequest;
import org.openqa.selenium.remote.http.HttpResponse;
import org.openqa.selenium.remote.tracing.DistributedTracer;
import org.openqa.selenium.remote.tracing.Span;

import java.io.IOException;
import java.io.UncheckedIOException;
Expand All @@ -58,12 +60,13 @@ public class LocalNode extends Node {
private final Cache<SessionId, SessionAndHandler> currentSessions;

private LocalNode(
DistributedTracer tracer,
URI uri,
int maxSessionCount,
Ticker ticker,
Duration sessionTimeout,
List<SessionFactory> factories) {
super(UUID.randomUUID());
super(tracer, UUID.randomUUID());

Preconditions.checkArgument(
maxSessionCount > 0,
Expand Down Expand Up @@ -92,65 +95,78 @@ public boolean isSupporting(Capabilities capabilities) {

@Override
public Optional<Session> newSession(Capabilities capabilities) {
if (getCurrentSessionCount() >= maxSessionCount) {
return Optional.empty();
}
try (Span span = createSpan("node-new-session")) {
span.addTag("capabilities", capabilities.toString());
if (getCurrentSessionCount() >= maxSessionCount) {
return Optional.empty();
}

Optional<SessionAndHandler> possibleSession = factories.stream()
.filter(factory -> factory.test(capabilities))
.map(factory -> factory.apply(capabilities))
.filter(Optional::isPresent)
.findFirst()
.map(Optional::get);
Optional<SessionAndHandler> possibleSession = factories.stream()
.filter(factory -> factory.test(capabilities))
.map(factory -> factory.apply(capabilities))
.filter(Optional::isPresent)
.findFirst()
.map(Optional::get);

if (!possibleSession.isPresent()) {
return Optional.empty();
}
if (!possibleSession.isPresent()) {
return Optional.empty();
}

SessionAndHandler session = possibleSession.get();
currentSessions.put(session.getId(), session);
SessionAndHandler session = possibleSession.get();
currentSessions.put(session.getId(), session);

// The session we return has to look like it came from the node, since we might be dealing
// with a webdriver implementation that only accepts connections from localhost
return Optional.of(new Session(session.getId(), externalUri, session.getCapabilities()));
// The session we return has to look like it came from the node, since we might be dealing
// with a webdriver implementation that only accepts connections from localhost
return Optional.of(new Session(session.getId(), externalUri, session.getCapabilities()));
}
}

@Override
protected boolean isSessionOwner(SessionId id) {
Objects.requireNonNull(id, "Session ID has not been set");
return currentSessions.getIfPresent(id) != null;
try (Span span = createSpan("node-is-session-owner")) {
span.addTag("session-id", String.valueOf(id));
Objects.requireNonNull(id, "Session ID has not been set");
return currentSessions.getIfPresent(id) != null;
}
}

@Override
public Session getSession(SessionId id) throws NoSuchSessionException {
Objects.requireNonNull(id, "Session ID has not been set");
SessionAndHandler session = currentSessions.getIfPresent(id);
if (session == null) {
throw new NoSuchSessionException("Cannot find session with id: " + id);
}
try (Span span = createSpan("node-get-session")) {
span.addTag("session-id", String.valueOf(id));
Objects.requireNonNull(id, "Session ID has not been set");
SessionAndHandler session = currentSessions.getIfPresent(id);
if (session == null) {
throw new NoSuchSessionException("Cannot find session with id: " + id);
}

return new Session(session.getId(), externalUri, session.getCapabilities());
return new Session(session.getId(), externalUri, session.getCapabilities());
}
}

@Override
public void executeWebDriverCommand(HttpRequest req, HttpResponse resp) {
// True enough to be good enough
if (!req.getUri().startsWith("/session/")) {
throw new UnsupportedCommandException(String.format(
"Unsupported command: (%s) %s", req.getMethod(), req.getMethod()));
}
try (Span span = createSpan("node-execute-webdriver-command")) {
// True enough to be good enough
if (!req.getUri().startsWith("/session/")) {
throw new UnsupportedCommandException(String.format(
"Unsupported command: (%s) %s", req.getMethod(), req.getMethod()));
}

String[] split = req.getUri().split("/", 4);
SessionId id = new SessionId(split[2]);
String[] split = req.getUri().split("/", 4);
SessionId id = new SessionId(split[2]);

SessionAndHandler session = currentSessions.getIfPresent(id);
if (session == null) {
throw new NoSuchSessionException("Cannot find session with id: " + id);
}
try {
session.getHandler().execute(req, resp);
} catch (IOException e) {
throw new UncheckedIOException(e);
span.addTag("session-id", String.valueOf(id));

SessionAndHandler session = currentSessions.getIfPresent(id);
if (session == null) {
throw new NoSuchSessionException("Cannot find session with id: " + id);
}
try {
session.getHandler().execute(req, resp);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
}

Expand Down Expand Up @@ -195,20 +211,22 @@ private Map<String, Object> toJson() {
.collect(Collectors.toSet()));
}

public static Builder builder(URI uri, SessionMap sessions) {
return new Builder(uri, sessions);
public static Builder builder(DistributedTracer tracer, URI uri, SessionMap sessions) {
return new Builder(tracer, uri, sessions);
}

public static class Builder {

private final DistributedTracer tracer;
private final URI uri;
private final SessionMap sessions;
private final ImmutableList.Builder<SessionFactory> factories;
private int maxCount = Runtime.getRuntime().availableProcessors() * 5;
private Ticker ticker = Ticker.systemTicker();
private Duration sessionTimeout = Duration.ofMinutes(5);

public Builder(URI uri, SessionMap sessions) {
public Builder(DistributedTracer tracer, URI uri, SessionMap sessions) {
this.tracer = Objects.requireNonNull(tracer);
this.uri = Objects.requireNonNull(uri);
this.sessions = Objects.requireNonNull(sessions);
this.factories = ImmutableList.builder();
Expand Down Expand Up @@ -238,7 +256,7 @@ public Builder sessionTimeout(Duration timeout) {
}

public LocalNode build() {
return new LocalNode(uri, maxCount, ticker, sessionTimeout, factories.build());
return new LocalNode(tracer, uri, maxCount, ticker, sessionTimeout, factories.build());
}

public Advanced advanced() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import org.openqa.selenium.remote.http.HttpClient;
import org.openqa.selenium.remote.http.HttpRequest;
import org.openqa.selenium.remote.http.HttpResponse;
import org.openqa.selenium.remote.tracing.DistributedTracer;

import java.io.IOException;
import java.io.UncheckedIOException;
Expand All @@ -56,11 +57,12 @@ public class RemoteNode extends Node {
private final Set<Capabilities> capabilities;

public RemoteNode(
DistributedTracer tracer,
UUID id,
URI externalUri,
Collection<Capabilities> capabilities,
HttpClient client) {
super(id);
super(tracer, id);
this.externalUri = Objects.requireNonNull(externalUri);
this.capabilities = ImmutableSet.copyOf(capabilities);

Expand Down
Loading

0 comments on commit 570f533

Please sign in to comment.