Chrome DevTools Protocol (CDP) bindings for Selenium WebDriver targeting Chromium version 85
—
Browser log capture and management for the Chrome DevTools Protocol v85. This functionality allows you to access browser logs with different severity levels and timestamps for debugging and monitoring purposes.
The main class for browser log management implementing the idealized Log interface.
/**
* Browser logging functionality for Chrome DevTools v85
*/
public class V85Log implements org.openqa.selenium.devtools.idealized.log.Log {
/**
* Creates a new V85Log instance
*/
public V85Log();
}Enable, disable, and clear browser logs.
/**
* Enables browser log collection
* @return Command to enable logging
*/
public Command<Void> enable();
/**
* Clears all collected browser logs
* @return Command to clear logs
*/
public Command<Void> clear();Usage Example:
import org.openqa.selenium.devtools.v85.V85Log;
V85Log log = domains.log();
// Enable log collection
devTools.send(log.enable());
// Clear existing logs
devTools.send(log.clear());Monitor new log entries as they are added by the browser.
/**
* Event fired when a new log entry is added
* @return Event for new log entries
*/
public Event<org.openqa.selenium.devtools.idealized.log.model.LogEntry> entryAdded();Usage Example:
// Listen for new log entries
devTools.addListener(log.entryAdded(), logEntry -> {
System.out.printf("[%s] %s: %s%n",
new Date(logEntry.getEntry().getTimestamp()),
logEntry.getEntry().getLevel(),
logEntry.getEntry().getMessage()
);
// Handle specific log levels
if (logEntry.getEntry().getLevel() == Level.SEVERE) {
handleSevereError(logEntry);
}
});import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.devtools.DevTools;
import org.openqa.selenium.devtools.v85.V85Domains;
import java.util.logging.Level;
ChromeDriver driver = new ChromeDriver();
DevTools devTools = driver.getDevTools();
devTools.createSession();
V85Domains domains = new V85Domains(devTools);
V85Log log = domains.log();
// Enable logging
devTools.send(log.enable());
// Set up log monitoring
devTools.addListener(log.entryAdded(), logEntry -> {
var entry = logEntry.getEntry();
// Format log message
String formattedLog = String.format(
"[%s] %s - %s: %s",
new Date(entry.getTimestamp()),
logEntry.getSource(),
entry.getLevel(),
entry.getMessage()
);
// Route to appropriate handler based on level
switch (entry.getLevel()) {
case SEVERE:
System.err.println("ERROR: " + formattedLog);
logToErrorSystem(formattedLog);
break;
case WARNING:
System.out.println("WARN: " + formattedLog);
logToWarningSystem(formattedLog);
break;
case INFO:
System.out.println("INFO: " + formattedLog);
break;
case FINEST:
if (debugMode) {
System.out.println("DEBUG: " + formattedLog);
}
break;
default:
System.out.println("LOG: " + formattedLog);
}
});
// Navigate to page - logs will be captured
driver.get("https://example.com");
// Clear logs when needed
devTools.send(log.clear());The V85Log class automatically converts Chrome DevTools Protocol log levels to Java logging levels:
/**
* Converts 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/**
* Converts CDP timestamp to Java long timestamp
* @param timestamp - CDP timestamp
* @return Java timestamp in milliseconds, or current time if parsing fails
*/
private long fromCdpTimestamp(Timestamp timestamp);Raw log entry from the Chrome DevTools Protocol.
/**
* Log entry from Chrome DevTools Protocol
*/
public class LogEntry {
/**
* Gets the log message source
* @return Log source (e.g., "javascript", "network", "storage")
*/
public Source getSource();
/**
* Gets the log level
* @return Log severity level
*/
public Level getLevel();
/**
* Gets the log message text
* @return Log message content
*/
public String getText();
/**
* Gets the timestamp when the log was created
* @return Log timestamp
*/
public Timestamp getTimestamp();
/**
* Gets the URL where the log originated (if applicable)
* @return Source URL
*/
public Optional<String> getUrl();
/**
* Gets the line number where the log originated (if applicable)
* @return Line number in source
*/
public Optional<Integer> getLineNumber();
/**
* Gets the stack trace for the log entry (if applicable)
* @return Stack trace information
*/
public Optional<StackTrace> getStackTrace();
/**
* Log severity levels in CDP
*/
public enum Level {
VERBOSE, INFO, WARNING, ERROR
}
/**
* Log sources in CDP
*/
public enum Source {
XML, JAVASCRIPT, NETWORK, STORAGE, APPCACHE, RENDERING,
SECURITY, DEPRECATION, WORKER, VIOLATION, INTERVENTION,
RECOMMENDATION, OTHER
}
}Selenium's idealized log entry that wraps CDP log data.
/**
* Selenium's idealized log entry wrapper
*/
public class org.openqa.selenium.devtools.idealized.log.model.LogEntry {
/**
* Creates a new idealized log entry
* @param source - Log source as string
* @param entry - Java LogEntry with level, timestamp, and message
*/
public LogEntry(String source, org.openqa.selenium.logging.LogEntry entry);
/**
* Gets the log source
* @return Source of the log entry
*/
public String getSource();
/**
* Gets the wrapped Java log entry
* @return Java LogEntry with standard logging information
*/
public org.openqa.selenium.logging.LogEntry getEntry();
}Standard Selenium log entry used by the idealized interface.
/**
* Standard Selenium log entry
*/
public class org.openqa.selenium.logging.LogEntry {
/**
* Gets the log level
* @return Java logging Level
*/
public Level getLevel();
/**
* Gets the timestamp in milliseconds
* @return Timestamp when log was created
*/
public long getTimestamp();
/**
* Gets the log message
* @return Log message text
*/
public String getMessage();
}// Filter logs by source and level
devTools.addListener(log.entryAdded(), logEntry -> {
String source = logEntry.getSource();
Level level = logEntry.getEntry().getLevel();
String message = logEntry.getEntry().getMessage();
// Only process JavaScript errors and network issues
if (source.equals("javascript") && level == Level.SEVERE) {
handleJavaScriptError(logEntry);
} else if (source.equals("network") && (level == Level.WARNING || level == Level.SEVERE)) {
handleNetworkIssue(logEntry);
}
// Filter by message content
if (message.contains("404") || message.contains("Failed to load")) {
handleResourceError(logEntry);
}
});
// Batch log processing
private final List<LogEntry> logBuffer = new ArrayList<>();
private final Timer logProcessor = new Timer();
devTools.addListener(log.entryAdded(), logEntry -> {
synchronized (logBuffer) {
logBuffer.add(logEntry);
// Process logs in batches every 5 seconds
if (logBuffer.size() == 1) {
logProcessor.schedule(new TimerTask() {
@Override
public void run() {
processBatchedLogs();
}
}, 5000);
}
}
});
private void processBatchedLogs() {
synchronized (logBuffer) {
if (!logBuffer.isEmpty()) {
// Process all buffered logs
logBuffer.forEach(this::processLogEntry);
logBuffer.clear();
}
}
}// Save logs to file
private final FileWriter logWriter = new FileWriter("browser-logs.txt", true);
devTools.addListener(log.entryAdded(), logEntry -> {
try {
String logLine = String.format(
"%s [%s] %s: %s%n",
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(logEntry.getEntry().getTimestamp())),
logEntry.getSource().toUpperCase(),
logEntry.getEntry().getLevel(),
logEntry.getEntry().getMessage()
);
logWriter.write(logLine);
logWriter.flush();
} catch (IOException e) {
System.err.println("Failed to write log: " + e.getMessage());
}
});
// Remember to close the writer when done
// logWriter.close();Install with Tessl CLI
npx tessl i tessl/maven-org-seleniumhq-selenium--selenium-devtools-v85