Skip to content

Commit 2d5436c

Browse files
Add HTTP response span for grid status. Add tracing for GraphqlHandler. (#8908)
Co-authored-by: David Burns <[email protected]>
1 parent 9a1aa93 commit 2d5436c

File tree

7 files changed

+106
-43
lines changed

7 files changed

+106
-43
lines changed

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ protected Handlers createHandlers(Config config) {
163163
handler.addHandler(distributor);
164164

165165
Router router = new Router(tracer, clientFactory, sessions, queuer, distributor);
166-
GraphqlHandler graphqlHandler = new GraphqlHandler(distributor, serverOptions.getExternalUri());
166+
GraphqlHandler graphqlHandler = new GraphqlHandler(tracer, distributor, serverOptions.getExternalUri());
167167
HttpHandler readinessCheck = req -> {
168168
boolean ready = router.isReady() && bus.isReady();
169169
return new HttpResponse()

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ protected Handlers createHandlers(Config config) {
171171
.setContent(Contents.utf8String("Standalone is " + ready));
172172
};
173173

174-
GraphqlHandler graphqlHandler = new GraphqlHandler(distributor, serverOptions.getExternalUri());
174+
GraphqlHandler graphqlHandler = new GraphqlHandler(tracer, distributor, serverOptions.getExternalUri());
175175

176176
Routable ui;
177177
URL uiRoot = getClass().getResource("/javascript/grid-ui/build");

java/server/src/org/openqa/selenium/grid/graphql/BUILD.bazel

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ java_library(
1515
"//java/client/src/org/openqa/selenium:core",
1616
"//java/client/src/org/openqa/selenium/json",
1717
"//java/client/src/org/openqa/selenium/remote/http",
18+
"//java/client/src/org/openqa/selenium/remote",
1819
"//java/server/src/org/openqa/selenium/grid/data",
1920
"//java/server/src/org/openqa/selenium/grid/distributor",
2021
artifact("com.google.guava:guava"),

java/server/src/org/openqa/selenium/grid/graphql/GraphqlHandler.java

+71-25
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,18 @@
2929
import graphql.schema.idl.SchemaParser;
3030
import graphql.schema.idl.TypeDefinitionRegistry;
3131
import org.openqa.selenium.grid.distributor.Distributor;
32+
import org.openqa.selenium.internal.Require;
3233
import org.openqa.selenium.json.Json;
3334
import org.openqa.selenium.remote.http.Contents;
3435
import org.openqa.selenium.remote.http.HttpHandler;
3536
import org.openqa.selenium.remote.http.HttpMethod;
3637
import org.openqa.selenium.remote.http.HttpRequest;
3738
import org.openqa.selenium.remote.http.HttpResponse;
39+
import org.openqa.selenium.remote.tracing.AttributeKey;
40+
import org.openqa.selenium.remote.tracing.EventAttribute;
41+
import org.openqa.selenium.remote.tracing.EventAttributeValue;
42+
import org.openqa.selenium.remote.tracing.Span;
43+
import org.openqa.selenium.remote.tracing.Tracer;
3844

3945
import java.io.IOException;
4046
import java.io.InputStream;
@@ -50,18 +56,26 @@
5056
import static org.openqa.selenium.json.Json.JSON_UTF_8;
5157
import static org.openqa.selenium.json.Json.MAP_TYPE;
5258
import static org.openqa.selenium.remote.http.Contents.utf8String;
59+
import static org.openqa.selenium.remote.tracing.HttpTracing.newSpanAsChildOf;
60+
import static org.openqa.selenium.remote.tracing.Tags.HTTP_RESPONSE;
61+
import static org.openqa.selenium.remote.tracing.Tags.HTTP_RESPONSE_EVENT;
62+
import static org.openqa.selenium.remote.tracing.Tags.HTTP_REQUEST;
63+
import static org.openqa.selenium.remote.tracing.Tags.HTTP_REQUEST_EVENT;
5364

5465
public class GraphqlHandler implements HttpHandler {
5566

5667
public static final String GRID_SCHEMA = "/org/openqa/selenium/grid/graphql/selenium-grid-schema.graphqls";
5768
public static final Json JSON = new Json();
69+
private final Tracer tracer;
5870
private final Distributor distributor;
5971
private final URI publicUri;
6072
private final GraphQL graphQl;
6173

62-
public GraphqlHandler(Distributor distributor, URI publicUri) {
63-
this.distributor = Objects.requireNonNull(distributor);
64-
this.publicUri = Objects.requireNonNull(publicUri);
74+
75+
public GraphqlHandler(Tracer tracer, Distributor distributor, URI publicUri) {
76+
this.distributor = Require.nonNull("Distributor", distributor);
77+
this.publicUri = Require.nonNull("Uri", publicUri);
78+
this.tracer = Require.nonNull("Tracer", tracer);
6579

6680
GraphQLSchema schema = new SchemaGenerator()
6781
.makeExecutableSchema(buildTypeDefinitionRegistry(), buildRuntimeWiring());
@@ -88,34 +102,66 @@ public GraphqlHandler(Distributor distributor, URI publicUri) {
88102

89103
@Override
90104
public HttpResponse execute(HttpRequest req) throws UncheckedIOException {
91-
Map<String, Object> inputs = JSON.toType(Contents.string(req), MAP_TYPE);
105+
try (Span span = newSpanAsChildOf(tracer, req, "grid.status")) {
106+
HttpResponse response;
107+
Map<String, Object> inputs = JSON.toType(Contents.string(req), MAP_TYPE);
92108

93-
if (!(inputs.get("query") instanceof String)) {
94-
return new HttpResponse()
95-
.setStatus(HTTP_INTERNAL_ERROR)
96-
.setContent(Contents.utf8String("Unable to find query"));
97-
}
109+
Map<String, EventAttributeValue> attributeMap = new HashMap<>();
110+
attributeMap.put(AttributeKey.LOGGER_CLASS.getKey(),
111+
EventAttribute.setValue(getClass().getName()));
98112

99-
String query = (String) inputs.get("query");
100-
@SuppressWarnings("unchecked") Map<String, Object> variables = inputs.get("variables") instanceof Map ?
101-
(Map<String, Object>) inputs.get("variables") :
102-
new HashMap<>();
113+
HTTP_REQUEST.accept(span, req);
114+
HTTP_REQUEST_EVENT.accept(attributeMap, req);
103115

104-
ExecutionInput executionInput = ExecutionInput.newExecutionInput(query)
105-
.variables(variables)
106-
.build();
116+
if (!(inputs.get("query") instanceof String)) {
117+
response = new HttpResponse()
118+
.setStatus(HTTP_INTERNAL_ERROR)
119+
.setContent(Contents.utf8String("Unable to find query"));
107120

108-
ExecutionResult result = graphQl.execute(executionInput);
121+
HTTP_RESPONSE.accept(span, response);
122+
HTTP_RESPONSE_EVENT.accept(attributeMap, response);
109123

110-
if (result.isDataPresent()) {
111-
return new HttpResponse()
112-
.addHeader("Content-Type", JSON_UTF_8)
113-
.setContent(utf8String(JSON.toJson(result.toSpecification())));
114-
}
124+
attributeMap.put(AttributeKey.EXCEPTION_MESSAGE.getKey(),
125+
EventAttribute.setValue("Unable to find query"));
126+
span.addEvent(AttributeKey.EXCEPTION_EVENT.getKey(), attributeMap);
127+
return response;
128+
}
129+
130+
String query = (String) inputs.get("query");
131+
@SuppressWarnings("unchecked") Map<String, Object> variables = inputs.get("variables") instanceof Map ?
132+
(Map<String, Object>) inputs.get("variables") :
133+
new HashMap<>();
134+
135+
ExecutionInput executionInput = ExecutionInput.newExecutionInput(query)
136+
.variables(variables)
137+
.build();
138+
139+
ExecutionResult result = graphQl.execute(executionInput);
115140

116-
return new HttpResponse()
117-
.setStatus(HTTP_INTERNAL_ERROR)
118-
.setContent(utf8String(JSON.toJson(result.getErrors())));
141+
if (result.isDataPresent()) {
142+
response = new HttpResponse()
143+
.addHeader("Content-Type", JSON_UTF_8)
144+
.setContent(utf8String(JSON.toJson(result.toSpecification())));
145+
146+
HTTP_RESPONSE.accept(span, response);
147+
HTTP_RESPONSE_EVENT.accept(attributeMap, response);
148+
span.addEvent("Graphql query executed", attributeMap);
149+
150+
return response;
151+
}
152+
153+
response = new HttpResponse()
154+
.setStatus(HTTP_INTERNAL_ERROR)
155+
.setContent(utf8String(JSON.toJson(result.getErrors())));
156+
HTTP_RESPONSE.accept(span, response);
157+
HTTP_RESPONSE_EVENT.accept(attributeMap, response);
158+
159+
attributeMap.put(AttributeKey.EXCEPTION_MESSAGE.getKey(),
160+
EventAttribute.setValue("Error while executing the query"));
161+
span.addEvent(AttributeKey.EXCEPTION_EVENT.getKey(), attributeMap);
162+
163+
return response;
164+
}
119165
}
120166

121167
private RuntimeWiring buildRuntimeWiring() {

java/server/src/org/openqa/selenium/grid/router/GridStatusHandler.java

+22-6
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@
5757
import static org.openqa.selenium.remote.tracing.Tags.EXCEPTION;
5858
import static org.openqa.selenium.remote.tracing.Tags.HTTP_RESPONSE;
5959
import static org.openqa.selenium.remote.tracing.Tags.HTTP_RESPONSE_EVENT;
60+
import static org.openqa.selenium.remote.tracing.Tags.HTTP_REQUEST;
61+
import static org.openqa.selenium.remote.tracing.Tags.HTTP_REQUEST_EVENT;
6062

6163
class GridStatusHandler implements HttpHandler {
6264

@@ -95,10 +97,14 @@ class GridStatusHandler implements HttpHandler {
9597
public HttpResponse execute(HttpRequest req) {
9698
long start = System.currentTimeMillis();
9799

98-
try (Span span = newSpanAsChildOf(tracer, req, "router.status")) {
100+
try (Span span = newSpanAsChildOf(tracer, req, "grid.status")) {
99101
Map<String, EventAttributeValue> attributeMap = new HashMap<>();
100102
attributeMap.put(AttributeKey.LOGGER_CLASS.getKey(),
101103
EventAttribute.setValue(getClass().getName()));
104+
105+
HTTP_REQUEST.accept(span, req);
106+
HTTP_REQUEST_EVENT.accept(attributeMap, req);
107+
102108
DistributorStatus status;
103109
try {
104110
status = EXECUTOR_SERVICE.submit(span.wrap(distributor::getStatus)).get(2, SECONDS);
@@ -108,24 +114,34 @@ public HttpResponse execute(HttpRequest req) {
108114
EXCEPTION.accept(attributeMap, e);
109115
attributeMap.put(AttributeKey.EXCEPTION_MESSAGE.getKey(),
110116
EventAttribute.setValue("Unable to get distributor status due to execution error or timeout: " + e.getMessage()));
111-
span.addEvent(AttributeKey.EXCEPTION_EVENT.getKey(), attributeMap);
112-
113-
return new HttpResponse().setContent(asJson(
117+
HttpResponse response = new HttpResponse().setContent(asJson(
114118
ImmutableMap.of("value", ImmutableMap.of(
115119
"ready", false,
116120
"message", "Unable to read distributor status."))));
121+
122+
HTTP_RESPONSE.accept(span, response);
123+
HTTP_RESPONSE_EVENT.accept(attributeMap, response);
124+
span.addEvent(AttributeKey.EXCEPTION_EVENT.getKey(), attributeMap);
125+
126+
return response;
117127
} catch (InterruptedException e) {
118128
span.setAttribute("error", true);
119129
span.setStatus(Status.ABORTED);
120130
EXCEPTION.accept(attributeMap, e);
121131
attributeMap.put(AttributeKey.EXCEPTION_MESSAGE.getKey(),
122132
EventAttribute.setValue("Interruption while getting distributor status: " + e.getMessage()));
123133

124-
Thread.currentThread().interrupt();
125-
return new HttpResponse().setContent(asJson(
134+
HttpResponse response = new HttpResponse().setContent(asJson(
126135
ImmutableMap.of("value", ImmutableMap.of(
127136
"ready", false,
128137
"message", "Reading distributor status was interrupted."))));
138+
139+
HTTP_RESPONSE.accept(span, response);
140+
HTTP_RESPONSE_EVENT.accept(attributeMap, response);
141+
span.addEvent(AttributeKey.EXCEPTION_EVENT.getKey(), attributeMap);
142+
143+
Thread.currentThread().interrupt();
144+
return response;
129145
}
130146

131147
boolean ready = status.hasCapacity();

java/server/src/org/openqa/selenium/grid/router/httpd/RouterServer.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ protected Handlers createHandlers(Config config) {
130130
distributorUrl,
131131
secretOptions.getRegistrationSecret());
132132

133-
GraphqlHandler graphqlHandler = new GraphqlHandler(distributor, serverOptions.getExternalUri());
133+
GraphqlHandler graphqlHandler = new GraphqlHandler(tracer, distributor, serverOptions.getExternalUri());
134134

135135
Route handler = Route.combine(
136136
new Router(tracer, clientFactory, sessions, queuer, distributor).with(networkOptions.getSpecComplianceChecks()),

java/server/test/org/openqa/selenium/grid/graphql/GraphqlHandlerTest.java

+9-9
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ public void setupGrid() {
119119

120120
@Test
121121
public void shouldBeAbleToGetGridUri() {
122-
GraphqlHandler handler = new GraphqlHandler(distributor, publicUri);
122+
GraphqlHandler handler = new GraphqlHandler(tracer, distributor, publicUri);
123123

124124
Map<String, Object> topLevel = executeQuery(handler, "{ grid { uri } }");
125125

@@ -132,7 +132,7 @@ public void shouldBeAbleToGetGridUri() {
132132

133133
@Test
134134
public void shouldReturnAnEmptyListForNodesIfNoneAreRegistered() {
135-
GraphqlHandler handler = new GraphqlHandler(distributor, publicUri);
135+
GraphqlHandler handler = new GraphqlHandler(tracer, distributor, publicUri);
136136

137137
Map<String, Object> topLevel = executeQuery(handler, "{ grid { nodes { uri } } }");
138138

@@ -163,7 +163,7 @@ public boolean test(Capabilities capabilities) {
163163
distributor.add(node);
164164
wait.until(obj -> distributor.getStatus().hasCapacity());
165165

166-
GraphqlHandler handler = new GraphqlHandler(distributor, publicUri);
166+
GraphqlHandler handler = new GraphqlHandler(tracer, distributor, publicUri);
167167
Map<String, Object> topLevel = executeQuery(handler, "{ grid { nodes { uri } } }");
168168

169169
assertThat(topLevel).describedAs(topLevel.toString()).isEqualTo(
@@ -209,7 +209,7 @@ public void shouldBeAbleToGetSessionInfo() throws URISyntaxException {
209209
String query = String.format(
210210
"{ session (id: \"%s\") { id, capabilities, startTime, uri } }", sessionId);
211211

212-
GraphqlHandler handler = new GraphqlHandler(distributor, publicUri);
212+
GraphqlHandler handler = new GraphqlHandler(tracer, distributor, publicUri);
213213
Map<String, Object> result = executeQuery(handler, query);
214214

215215
assertThat(result).describedAs(result.toString()).isEqualTo(
@@ -257,7 +257,7 @@ public void shouldBeAbleToGetNodeInfoForSession() throws URISyntaxException {
257257
slot);
258258
String query = String.format("{ session (id: \"%s\") { nodeId, nodeUri } }", sessionId);
259259

260-
GraphqlHandler handler = new GraphqlHandler(distributor, publicUri);
260+
GraphqlHandler handler = new GraphqlHandler(tracer, distributor, publicUri);
261261
Map<String, Object> result = executeQuery(handler, query);
262262

263263
assertThat(result).describedAs(result.toString()).isEqualTo(
@@ -307,7 +307,7 @@ public void shouldBeAbleToGetSlotInfoForSession() throws URISyntaxException {
307307
String query = String.format(
308308
"{ session (id: \"%s\") { slot { id, stereotype, lastStarted } } }", sessionId);
309309

310-
GraphqlHandler handler = new GraphqlHandler(distributor, publicUri);
310+
GraphqlHandler handler = new GraphqlHandler(tracer, distributor, publicUri);
311311
Map<String, Object> result = executeQuery(handler, query);
312312

313313
assertThat(result).describedAs(result.toString()).isEqualTo(
@@ -342,7 +342,7 @@ public void shouldBeAbleToGetSessionDuration() throws URISyntaxException {
342342

343343
String query = String.format("{ session (id: \"%s\") { sessionDurationMillis } }", sessionId);
344344

345-
GraphqlHandler handler = new GraphqlHandler(distributor, publicUri);
345+
GraphqlHandler handler = new GraphqlHandler(tracer, distributor, publicUri);
346346
Map<String, Object> result = executeQuery(handler, query);
347347

348348
assertThat(result)
@@ -370,7 +370,7 @@ public void shouldThrowExceptionWhenSessionNotFound() throws URISyntaxException
370370
String randomSessionId = UUID.randomUUID().toString();
371371
String query = "{ session (id: \"" + randomSessionId + "\") { sessionDurationMillis } }";
372372

373-
GraphqlHandler handler = new GraphqlHandler(distributor, publicUri);
373+
GraphqlHandler handler = new GraphqlHandler(tracer, distributor, publicUri);
374374
Map<String, Object> result = executeQuery(handler, query);
375375
assertThat(result)
376376
.containsEntry("data", null)
@@ -399,7 +399,7 @@ public void shouldThrowExceptionWhenSessionIsEmpty() throws URISyntaxException {
399399

400400
String query = "{ session (id: \"\") { sessionDurationMillis } }";
401401

402-
GraphqlHandler handler = new GraphqlHandler(distributor, publicUri);
402+
GraphqlHandler handler = new GraphqlHandler(tracer, distributor, publicUri);
403403
Map<String, Object> result = executeQuery(handler, query);
404404
assertThat(result)
405405
.containsEntry("data", null)

0 commit comments

Comments
 (0)