WebDriver remote communication library that provides the core infrastructure for browser automation across different platforms and programming languages.
—
OpenTelemetry-based distributed tracing support for observability in distributed testing environments. This system provides comprehensive instrumentation for WebDriver operations, enabling performance monitoring, debugging, and analysis of complex test execution flows across multiple services and infrastructure components.
Core tracing interface providing context management, span creation, and trace propagation.
/**
* Main tracing interface for creating and managing distributed traces
*/
public interface Tracer {
/**
* Get the current trace context
* @return Current trace context
*/
TraceContext getCurrentContext();
/**
* Get the propagator for trace context propagation
* @return Trace context propagator
*/
Propagator getPropagator();
/**
* Create a new attribute map for span attributes
* @return New attribute map instance
*/
AttributeMap createAttributeMap();
}Usage Examples:
import org.openqa.selenium.remote.tracing.opentelemetry.OpenTelemetryTracer;
import org.openqa.selenium.remote.tracing.Tracer;
// Get tracer instance
Tracer tracer = OpenTelemetryTracer.getInstance();
// Get current context
TraceContext currentContext = tracer.getCurrentContext();
// Create child context for operation
TraceContext childContext = currentContext.createChild("webdriver-operation");Represents a single operation within a distributed trace, providing methods for adding metadata, events, and status information.
/**
* Represents a trace span - a single operation within a distributed trace
*/
public interface Span extends Closeable {
/**
* Set the span name
* @param name Operation name
* @return This span for chaining
*/
Span setName(String name);
/**
* Add string tag to span
* @param key Tag key
* @param value Tag value
* @return This span for chaining
*/
Span addTag(String key, String value);
/**
* Add boolean tag to span
* @param key Tag key
* @param value Tag value
* @return This span for chaining
*/
Span addTag(String key, boolean value);
/**
* Add numeric tag to span
* @param key Tag key
* @param value Tag value
* @return This span for chaining
*/
Span addTag(String key, long value);
/**
* Add double tag to span
* @param key Tag key
* @param value Tag value
* @return This span for chaining
*/
Span addTag(String key, double value);
/**
* Add event to span
* @param name Event name
* @return This span for chaining
*/
Span addEvent(String name);
/**
* Add event with attributes to span
* @param name Event name
* @param attributeMap Event attributes
* @return This span for chaining
*/
Span addEvent(String name, AttributeMap attributeMap);
/**
* Set span status
* @param status Span status
* @return This span for chaining
*/
Span setStatus(Status status);
/**
* Close and finish the span
*/
void close();
}Usage Examples:
import org.openqa.selenium.remote.tracing.Span;
import org.openqa.selenium.remote.tracing.Status;
// Create and configure span
TraceContext context = tracer.getCurrentContext();
TraceContext childContext = context.createChild("find-element");
try (Span span = childContext.getActiveSpan()) {
span.setName("findElement")
.addTag("locator.type", "id")
.addTag("locator.value", "submit-button")
.addTag("timeout.ms", 10000);
// Perform operation
WebElement element = driver.findElement(By.id("submit-button"));
// Add success event
span.addEvent("element-found")
.addTag("element.tag", element.getTagName())
.setStatus(Status.OK);
} catch (NoSuchElementException e) {
// Handle error in span
span.addEvent("element-not-found")
.addTag("error", true)
.addTag("error.message", e.getMessage())
.setStatus(Status.NOT_FOUND);
throw e;
}Manages trace context and span hierarchy, providing methods for creating child contexts and accessing active spans.
/**
* Manages trace context and span hierarchy
*/
public interface TraceContext {
/**
* Create child context for nested operation
* @param operationName Name of the child operation
* @return Child trace context
*/
TraceContext createChild(String operationName);
/**
* Get the currently active span
* @return Active span instance
*/
Span getActiveSpan();
}Usage Examples:
// Create nested trace contexts
TraceContext rootContext = tracer.getCurrentContext();
TraceContext pageContext = rootContext.createChild("page-operations");
TraceContext elementContext = pageContext.createChild("element-interaction");
// Work with active spans
Span pageSpan = pageContext.getActiveSpan();
pageSpan.setName("navigate-to-page")
.addTag("url", "https://example.com");
Span elementSpan = elementContext.getActiveSpan();
elementSpan.setName("click-button")
.addTag("element.id", "submit");Type-safe attribute management for spans, supporting different value types with proper serialization.
/**
* Type-safe attribute management for spans
*/
public interface AttributeMap {
/**
* Add boolean attribute
* @param key Attribute key
* @param value Boolean value
* @return This attribute map for chaining
*/
AttributeMap put(AttributeKey<Boolean> key, Boolean value);
/**
* Add long attribute
* @param key Attribute key
* @param value Long value
* @return This attribute map for chaining
*/
AttributeMap put(AttributeKey<Long> key, Long value);
/**
* Add string attribute
* @param key Attribute key
* @param value String value
* @return This attribute map for chaining
*/
AttributeMap put(AttributeKey<String> key, String value);
}Typed keys for span attributes ensuring type safety and proper serialization.
/**
* Typed keys for span attributes
*/
public class AttributeKey<T> {
/**
* Create boolean attribute key
* @param key Key name
* @return Boolean attribute key
*/
public static AttributeKey<Boolean> booleanKey(String key);
/**
* Create long attribute key
* @param key Key name
* @return Long attribute key
*/
public static AttributeKey<Long> longKey(String key);
/**
* Create string attribute key
* @param key Key name
* @return String attribute key
*/
public static AttributeKey<String> stringKey(String key);
}Usage Examples:
import org.openqa.selenium.remote.tracing.AttributeKey;
import org.openqa.selenium.remote.tracing.AttributeMap;
// Define typed attribute keys
AttributeKey<String> urlKey = AttributeKey.stringKey("http.url");
AttributeKey<Long> durationKey = AttributeKey.longKey("operation.duration");
AttributeKey<Boolean> successKey = AttributeKey.booleanKey("operation.success");
// Create attribute map
AttributeMap attributes = tracer.createAttributeMap()
.put(urlKey, "https://example.com")
.put(durationKey, 1500L)
.put(successKey, true);
// Use with span events
span.addEvent("http-request-completed", attributes);Command executor wrapper that automatically traces all WebDriver command executions.
/**
* Command executor that adds distributed tracing to all WebDriver commands
*/
public class TracedCommandExecutor implements CommandExecutor {
/**
* Create traced command executor
* @param executor Underlying command executor
* @param tracer Tracer instance for creating spans
*/
public TracedCommandExecutor(CommandExecutor executor, Tracer tracer);
/**
* Execute command with tracing
* @param command WebDriver command to execute
* @return Command response
*/
public Response execute(Command command);
}Usage Examples:
import org.openqa.selenium.remote.TracedCommandExecutor;
import org.openqa.selenium.remote.HttpCommandExecutor;
// Create traced WebDriver
URL gridUrl = new URL("http://selenium-grid:4444/wd/hub");
CommandExecutor baseExecutor = new HttpCommandExecutor(gridUrl);
Tracer tracer = OpenTelemetryTracer.getInstance();
CommandExecutor tracedExecutor = new TracedCommandExecutor(baseExecutor, tracer);
// Use with RemoteWebDriver - all commands will be traced
RemoteWebDriver driver = new RemoteWebDriver(tracedExecutor, capabilities);
// Every WebDriver operation will create trace spans
driver.get("https://example.com"); // Creates "get" span
driver.findElement(By.id("btn")); // Creates "findElement" span
driver.quit(); // Creates "quit" spanProduction-ready OpenTelemetry-based implementation of the tracing interfaces.
/**
* OpenTelemetry-based tracer implementation
*/
public class OpenTelemetryTracer implements Tracer {
/**
* Get singleton tracer instance
* @return OpenTelemetry tracer instance
*/
public static Tracer getInstance();
// Tracer interface implementation
public TraceContext getCurrentContext();
public Propagator getPropagator();
public AttributeMap createAttributeMap();
}No-op implementations for production environments where tracing is disabled.
/**
* No-op tracer implementation for environments without tracing
*/
public class NullTracer implements Tracer {
public TraceContext getCurrentContext();
public Propagator getPropagator();
public AttributeMap createAttributeMap();
}
/**
* No-op span implementation
*/
public class NullSpan implements Span {
public Span setName(String name);
public Span addTag(String key, String value);
public Span addTag(String key, boolean value);
public Span addTag(String key, long value);
public Span addTag(String key, double value);
public Span addEvent(String name);
public Span addEvent(String name, AttributeMap attributeMap);
public Span setStatus(Status status);
public void close();
}// Manual span creation for custom operations
TraceContext context = tracer.getCurrentContext();
TraceContext customContext = context.createChild("custom-test-setup");
try (Span span = customContext.getActiveSpan()) {
span.setName("test-data-preparation")
.addTag("test.name", "loginTest")
.addTag("test.suite", "authentication");
// Perform setup operations
setupTestData();
span.addEvent("test-data-ready")
.setStatus(Status.OK);
}// Extract trace context from HTTP headers
Map<String, String> headers = getIncomingHttpHeaders();
Propagator propagator = tracer.getPropagator();
TraceContext extractedContext = propagator.extract(headers);
// Inject trace context into outgoing HTTP requests
Map<String, String> outgoingHeaders = new HashMap<>();
propagator.inject(tracer.getCurrentContext(), outgoingHeaders);
httpRequest.setHeaders(outgoingHeaders);// Monitor WebDriver operation performance
long startTime = System.currentTimeMillis();
try (Span span = context.createChild("page-load").getActiveSpan()) {
span.setName("navigate-and-wait")
.addTag("url", targetUrl)
.addTag("expected.title", expectedTitle);
driver.get(targetUrl);
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
wait.until(ExpectedConditions.titleContains(expectedTitle));
long duration = System.currentTimeMillis() - startTime;
span.addTag("duration.ms", duration)
.addTag("performance.slow", duration > 5000)
.setStatus(Status.OK);
if (duration > 5000) {
span.addEvent("slow-page-load-detected");
}
}// Comprehensive error tracking in spans
try (Span span = context.createChild("element-interaction").getActiveSpan()) {
span.setName("click-element")
.addTag("element.locator", locator.toString())
.addTag("retry.attempt", retryCount);
try {
WebElement element = driver.findElement(locator);
element.click();
span.addTag("element.found", true)
.addTag("element.tag", element.getTagName())
.setStatus(Status.OK);
} catch (NoSuchElementException e) {
span.addTag("element.found", false)
.addTag("error.type", "NoSuchElementException")
.addTag("error.message", e.getMessage())
.addEvent("element-not-found")
.setStatus(Status.NOT_FOUND);
throw e;
} catch (ElementNotInteractableException e) {
span.addTag("element.found", true)
.addTag("element.interactable", false)
.addTag("error.type", "ElementNotInteractableException")
.addEvent("element-not-interactable")
.setStatus(Status.FAILED_PRECONDITION);
throw e;
}
}// JUnit integration example
@BeforeEach
void setupTracing() {
TraceContext testContext = tracer.getCurrentContext()
.createChild(testInfo.getDisplayName());
Span testSpan = testContext.getActiveSpan();
testSpan.setName("test-execution")
.addTag("test.class", testInfo.getTestClass().get().getSimpleName())
.addTag("test.method", testInfo.getTestMethod().get().getName());
}
@AfterEach
void finishTracing(TestInfo testInfo) {
Span testSpan = tracer.getCurrentContext().getActiveSpan();
if (testExecutionResult.wasSuccessful()) {
testSpan.setStatus(Status.OK);
} else {
testSpan.addTag("test.failed", true)
.setStatus(Status.ABORTED);
}
testSpan.close();
}Install with Tessl CLI
npx tessl i tessl/maven-org-seleniumhq-selenium--selenium-remote-driver