Chrome DevTools Protocol version 99 support library for Selenium WebDriver Java bindings
—
Browser console and log event collection with level filtering and timestamp handling for comprehensive logging support. Provides access to browser-side logging events for monitoring and debugging web applications.
Creates a log management handler for Chrome DevTools Protocol v99.
/**
* Log management implementation for CDP v99
* Implements the idealized Log interface
*/
public class V99Log implements org.openqa.selenium.devtools.idealized.log.Log;Enable and disable browser log collection.
/**
* Enable log domain for collecting browser logs
* @return Command to enable log collection
*/
public Command<Void> enable();
/**
* Clear all browser console logs
* @return Command to clear logs
*/
public Command<Void> clear();Monitor browser log entries as they are generated.
/**
* Get event handler for new log entries
* @return Event for log entry additions
*/
public Event<LogEntry> entryAdded();/**
* Browser log entry from CDP
*/
public class LogEntry {
/**
* Get log entry source (console, network, etc.)
* @return Log source
*/
public LogSource getSource();
/**
* Get log level (verbose, info, warning, error)
* @return Log level
*/
public Level getLevel();
/**
* Get log message text
* @return Message string
*/
public String getText();
/**
* Get timestamp when log entry was created
* @return Timestamp
*/
public Timestamp getTimestamp();
/**
* Get URL where log entry originated
* @return Optional URL
*/
public Optional<String> getUrl();
/**
* Get line number where log entry originated
* @return Optional line number
*/
public Optional<Integer> getLineNumber();
/**
* Get stack trace if available
* @return Optional stack trace
*/
public Optional<StackTrace> getStackTrace();
/**
* Get network request ID if log is network-related
* @return Optional network request ID
*/
public Optional<NetworkRequestId> getNetworkRequestId();
/**
* Get worker ID if log originated from web worker
* @return Optional worker ID
*/
public Optional<WorkerId> getWorkerId();
/**
* Get additional arguments for the log entry
* @return Optional list of remote objects
*/
public Optional<List<RemoteObject>> getArgs();
}
/**
* Log entry source types
*/
public enum LogSource {
XML("xml"),
JAVASCRIPT("javascript"),
NETWORK("network"),
STORAGE("storage"),
APPCACHE("appcache"),
RENDERING("rendering"),
SECURITY("security"),
DEPRECATION("deprecation"),
WORKER("worker"),
VIOLATION("violation"),
INTERVENTION("intervention"),
RECOMMENDATION("recommendation"),
OTHER("other");
}
/**
* Log level enumeration
*/
public enum Level {
VERBOSE("verbose"),
INFO("info"),
WARNING("warning"),
ERROR("error");
}/**
* Selenium log entry (converted from CDP log entry)
*/
public class org.openqa.selenium.devtools.idealized.log.model.LogEntry {
/**
* Create Selenium log entry
* @param source - Log source string
* @param entry - Selenium logging LogEntry
*/
public LogEntry(String source, org.openqa.selenium.logging.LogEntry entry);
/**
* Get log source
* @return Source string
*/
public String getSource();
/**
* Get Selenium log entry
* @return Selenium LogEntry
*/
public org.openqa.selenium.logging.LogEntry getLogEntry();
}
/**
* Standard Selenium log entry
*/
public class org.openqa.selenium.logging.LogEntry {
/**
* Get log level
* @return Java logging Level
*/
public Level getLevel();
/**
* Get timestamp in milliseconds
* @return Timestamp
*/
public long getTimestamp();
/**
* Get log message
* @return Message string
*/
public String getMessage();
}The V99Log implementation converts CDP log levels to Java logging levels:
/**
* Convert CDP log level to Java logging level
* @param level - CDP log level
* @return Java logging Level
*/
private Level fromCdpLevel(LogEntry.Level level);Level Mapping:
verbose → Level.FINESTinfo → Level.INFOwarning → Level.WARNINGerror → Level.SEVERELevel.INFO (default)/**
* Convert CDP timestamp to milliseconds
* @param timestamp - CDP timestamp
* @return Milliseconds since epoch
*/
private long fromCdpTimestamp(Timestamp timestamp);import org.openqa.selenium.devtools.DevTools;
import org.openqa.selenium.devtools.v99.V99Domains;
import org.openqa.selenium.logging.LogEntry;
DevTools devTools = ...; // from ChromeDriver
V99Domains domains = new V99Domains(devTools);
// Enable log collection
devTools.send(domains.log().enable());
// Listen for log entries
devTools.addListener(domains.log().entryAdded(), logEntry -> {
String source = logEntry.getSource();
LogEntry seleniumLogEntry = logEntry.getLogEntry();
System.out.printf("[%s] %s - %s: %s%n",
new Date(seleniumLogEntry.getTimestamp()),
source,
seleniumLogEntry.getLevel(),
seleniumLogEntry.getMessage()
);
});
// Navigate to page - logs will be captured
driver.get("https://example.com");devTools.send(domains.log().enable());
devTools.addListener(domains.log().entryAdded(), logEntry -> {
LogEntry seleniumEntry = logEntry.getLogEntry();
Level level = seleniumEntry.getLevel();
// Only process warnings and errors
if (level == Level.WARNING || level == Level.SEVERE) {
System.err.printf("IMPORTANT: [%s] %s: %s%n",
logEntry.getSource(),
level,
seleniumEntry.getMessage()
);
// Could trigger alerts, save to special log, etc.
handleImportantLogEntry(logEntry);
}
});devTools.send(domains.log().enable());
devTools.addListener(domains.log().entryAdded(), logEntry -> {
String source = logEntry.getSource();
LogEntry seleniumEntry = logEntry.getLogEntry();
switch (source) {
case "network":
handleNetworkLog(seleniumEntry);
break;
case "javascript":
handleJavaScriptLog(seleniumEntry);
break;
case "security":
handleSecurityLog(seleniumEntry);
break;
case "deprecation":
handleDeprecationLog(seleniumEntry);
break;
default:
handleGenericLog(source, seleniumEntry);
}
});
private void handleNetworkLog(LogEntry entry) {
// Process network-related logs
if (entry.getLevel() == Level.SEVERE) {
System.err.println("Network Error: " + entry.getMessage());
}
}
private void handleSecurityLog(LogEntry entry) {
// Security logs are always important
System.err.println("SECURITY: " + entry.getMessage());
// Could trigger security alerts, audit logging, etc.
}import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
// Collect logs for later analysis
Queue<org.openqa.selenium.devtools.idealized.log.model.LogEntry> collectedLogs =
new ConcurrentLinkedQueue<>();
Map<String, AtomicInteger> logCounts = new ConcurrentHashMap<>();
devTools.send(domains.log().enable());
devTools.addListener(domains.log().entryAdded(), logEntry -> {
// Collect all logs
collectedLogs.offer(logEntry);
// Count by source
String source = logEntry.getSource();
logCounts.computeIfAbsent(source, k -> new AtomicInteger(0)).incrementAndGet();
// Count by level
Level level = logEntry.getLogEntry().getLevel();
logCounts.computeIfAbsent(level.toString(), k -> new AtomicInteger(0)).incrementAndGet();
});
// After test execution, analyze collected logs
public void analyzeLogs() {
System.out.println("Log Analysis:");
System.out.println("Total logs: " + collectedLogs.size());
logCounts.forEach((key, count) -> {
System.out.println(key + ": " + count.get());
});
// Find all error-level logs
List<org.openqa.selenium.devtools.idealized.log.model.LogEntry> errors =
collectedLogs.stream()
.filter(entry -> entry.getLogEntry().getLevel() == Level.SEVERE)
.collect(Collectors.toList());
if (!errors.isEmpty()) {
System.err.println("Found " + errors.size() + " error-level logs:");
errors.forEach(error -> {
System.err.println(" " + error.getSource() + ": " +
error.getLogEntry().getMessage());
});
}
}// Clear logs before starting a test
devTools.send(domains.log().clear());
devTools.send(domains.log().enable());
// Perform test operations
performTestSteps();
// Clear logs between test phases
devTools.send(domains.log().clear());
// Continue with next test phase
performNextTestPhase();import org.openqa.selenium.logging.LogType;
import org.openqa.selenium.logging.LoggingPreferences;
import org.openqa.selenium.chrome.ChromeOptions;
// Configure Chrome logging preferences
LoggingPreferences loggingPrefs = new LoggingPreferences();
loggingPrefs.enable(LogType.BROWSER, Level.ALL);
loggingPrefs.enable(LogType.PERFORMANCE, Level.INFO);
ChromeOptions options = new ChromeOptions();
options.setCapability("goog:loggingPrefs", loggingPrefs);
WebDriver driver = new ChromeDriver(options);
// Use both DevTools log monitoring and standard Selenium logs
DevTools devTools = ((ChromeDriver) driver).getDevTools();
devTools.createSession();
V99Domains domains = new V99Domains(devTools);
devTools.send(domains.log().enable());
// DevTools log monitoring (real-time)
devTools.addListener(domains.log().entryAdded(), logEntry -> {
// Real-time log processing
processLogEntryRealTime(logEntry);
});
// Standard Selenium log retrieval (after page load)
LogEntries browserLogs = driver.manage().logs().get(LogType.BROWSER);
for (LogEntry entry : browserLogs) {
// Process accumulated logs
processLogEntryBatch(entry);
}Log management operations can encounter various issues:
Handle errors through proper exception handling and resource management:
try {
devTools.send(domains.log().enable());
// Set up log monitoring
setupLogMonitoring();
// Perform operations
runTestOperations();
} catch (DevToolsException e) {
System.err.println("Failed to enable log monitoring: " + e.getMessage());
} finally {
// Note: CDP Log domain doesn't have explicit disable
// It's cleaned up when DevTools session ends
}Install with Tessl CLI
npx tessl i tessl/maven-org-seleniumhq-selenium--selenium-devtools-v99