Java bindings for Chrome DevTools Protocol version 102, providing programmatic access to Chrome browser debugging and automation capabilities
—
Manages console log operations, log entries, and provides conversion between CDP log formats and Selenium's logging system. This domain enables comprehensive monitoring of browser console output including different log levels and sources.
Main class for console log management. Implements the idealized Log interface to provide v102-specific implementations for log monitoring and entry processing.
/**
* Manages console log operations and entries
*/
public class V102Log implements org.openqa.selenium.devtools.idealized.log.Log {
/**
* Enables the Log domain to start receiving log entries
* @return Command to enable log domain
*/
public Command<Void> enable();
/**
* Clears all existing log entries
* @return Command to clear log entries
*/
public Command<Void> clear();
/**
* Returns the log entry added event for monitoring new log entries
* @return Event for log entry notifications with idealized log entry format
*/
public Event<org.openqa.selenium.devtools.idealized.log.model.LogEntry> entryAdded();
}Usage Examples:
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.devtools.DevTools;
import org.openqa.selenium.devtools.v102.V102Domains;
import org.openqa.selenium.devtools.idealized.log.model.LogEntry;
import java.util.logging.Level;
// Setup
ChromeDriver driver = new ChromeDriver();
DevTools devTools = driver.getDevTools();
devTools.createSession();
V102Domains domains = new V102Domains(devTools);
// Enable log domain
devTools.send(domains.log().enable());
// Listen for log entries
devTools.addListener(domains.log().entryAdded(), (logEntry) -> {
System.out.println(String.format(
"[%s] %s: %s",
logEntry.getSource(),
logEntry.getEntry().getLevel(),
logEntry.getEntry().getMessage()
));
});
// Navigate to a page that generates console output
driver.get("https://example.com");
// Execute JavaScript that logs messages
driver.executeScript("console.log('This is an info message');");
driver.executeScript("console.warn('This is a warning message');");
driver.executeScript("console.error('This is an error message');");
// Clear log entries
devTools.send(domains.log().clear());
// Cleanup
driver.quit();import java.util.logging.Level;
// Monitor only specific log levels
devTools.addListener(domains.log().entryAdded(), (logEntry) -> {
Level level = logEntry.getEntry().getLevel();
String message = logEntry.getEntry().getMessage();
String source = logEntry.getSource();
switch (level.getName()) {
case "SEVERE": // Error level
System.err.println("ERROR [" + source + "]: " + message);
break;
case "WARNING": // Warning level
System.out.println("WARN [" + source + "]: " + message);
break;
case "INFO": // Info level
System.out.println("INFO [" + source + "]: " + message);
break;
case "FINEST": // Verbose level
System.out.println("VERBOSE [" + source + "]: " + message);
break;
default:
System.out.println("LOG [" + source + "] " + level + ": " + message);
}
});import java.util.concurrent.CopyOnWriteArrayList;
import java.time.Instant;
// Collect logs for analysis
List<LogEntry> collectedLogs = new CopyOnWriteArrayList<>();
devTools.addListener(domains.log().entryAdded(), (logEntry) -> {
collectedLogs.add(logEntry);
// Analyze log patterns
String message = logEntry.getEntry().getMessage();
if (message.contains("error") || message.contains("failed")) {
System.err.println("Potential issue detected: " + message);
}
});
// Perform test actions
driver.get("https://complex-app.com");
// ... perform various actions ...
// Analyze collected logs
System.out.println("Total log entries: " + collectedLogs.size());
long errorCount = collectedLogs.stream()
.filter(entry -> entry.getEntry().getLevel() == Level.SEVERE)
.count();
long warningCount = collectedLogs.stream()
.filter(entry -> entry.getEntry().getLevel() == Level.WARNING)
.count();
System.out.println("Errors: " + errorCount + ", Warnings: " + warningCount);
// Clear collected logs for next test
collectedLogs.clear();
devTools.send(domains.log().clear());// Filter logs by source
devTools.addListener(domains.log().entryAdded(), (logEntry) -> {
String source = logEntry.getSource();
String message = logEntry.getEntry().getMessage();
switch (source) {
case "javascript":
System.out.println("JS: " + message);
break;
case "network":
System.out.println("NET: " + message);
break;
case "storage":
System.out.println("STORAGE: " + message);
break;
case "appcache":
System.out.println("APPCACHE: " + message);
break;
case "rendering":
System.out.println("RENDER: " + message);
break;
case "security":
System.out.println("SECURITY: " + message);
break;
case "deprecation":
System.out.println("DEPRECATED: " + message);
break;
case "worker":
System.out.println("WORKER: " + message);
break;
case "violation":
System.out.println("VIOLATION: " + message);
break;
case "intervention":
System.out.println("INTERVENTION: " + message);
break;
case "recommendation":
System.out.println("RECOMMENDATION: " + message);
break;
default:
System.out.println("OTHER [" + source + "]: " + message);
}
});The V102Log class provides automatic conversion between CDP log levels and Java logging levels:
/**
* Internal level conversion (handled automatically by V102Log)
*/
private Level fromCdpLevel(LogEntry.Level level) {
switch (level.toString()) {
case "verbose":
return Level.FINEST; // Most detailed
case "info":
return Level.INFO; // General information
case "warning":
return Level.WARNING; // Warning messages
case "error":
return Level.SEVERE; // Error messages
default:
return Level.INFO; // Default fallback
}
}/**
* Internal timestamp conversion (handled automatically by V102Log)
*/
private long fromCdpTimestamp(Timestamp timestamp) {
try {
return Long.parseLong(timestamp.toString());
} catch (NumberFormatException e) {
return System.currentTimeMillis(); // Fallback to current time
}
}The V102Log class interacts with generated CDP protocol classes:
// Generated CDP log classes (available at runtime)
class Log {
static Command<Void> enable();
static Command<Void> clear();
static Event<LogEntry> entryAdded();
}
// CDP log entry representation
class LogEntry {
enum Level {
VERBOSE, INFO, WARNING, ERROR
}
String getSource();
Level getLevel();
String getText();
Timestamp getTimestamp();
Optional<String> getUrl();
Optional<Integer> getLineNumber();
Optional<StackTrace> getStackTrace();
}
// Timestamp representation
class Timestamp {
String toString();
JsonElement toJson();
}// Idealized log entry for Selenium integration
class org.openqa.selenium.devtools.idealized.log.model.LogEntry {
/**
* Creates idealized log entry with source and standard log entry
*/
LogEntry(String source, org.openqa.selenium.logging.LogEntry entry);
String getSource();
org.openqa.selenium.logging.LogEntry getEntry();
}
// Standard Selenium log entry
class org.openqa.selenium.logging.LogEntry {
LogEntry(Level level, long timestamp, String message);
Level getLevel();
long getTimestamp();
String getMessage();
}
// Java logging levels
enum Level {
FINEST, // Verbose
INFO, // Info
WARNING, // Warning
SEVERE // Error
}The log processing follows this flow:
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
// Buffer logs for batch processing
BlockingQueue<LogEntry> logBuffer = new LinkedBlockingQueue<>();
devTools.addListener(domains.log().entryAdded(), (logEntry) -> {
logBuffer.offer(logEntry);
});
// Process logs in background thread
Thread logProcessor = new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) {
try {
LogEntry entry = logBuffer.take(); // Blocks until available
processLogEntry(entry);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
});
logProcessor.start();import java.io.FileWriter;
import java.io.IOException;
import java.time.Instant;
import java.time.format.DateTimeFormatter;
// Write logs to file
FileWriter logFile = new FileWriter("console-logs.txt", true);
devTools.addListener(domains.log().entryAdded(), (logEntry) -> {
try {
String timestamp = DateTimeFormatter.ISO_INSTANT
.format(Instant.ofEpochMilli(logEntry.getEntry().getTimestamp()));
String logLine = String.format(
"%s [%s] %s: %s%n",
timestamp,
logEntry.getSource(),
logEntry.getEntry().getLevel(),
logEntry.getEntry().getMessage()
);
logFile.write(logLine);
logFile.flush();
} catch (IOException e) {
System.err.println("Failed to write log entry: " + e.getMessage());
}
});
// Remember to close file when done
// logFile.close();// Monitor logs only during specific operations
boolean monitoringEnabled = false;
devTools.addListener(domains.log().entryAdded(), (logEntry) -> {
if (monitoringEnabled) {
// Process log entry only when monitoring is enabled
handleLogEntry(logEntry);
}
});
// Enable monitoring for specific operation
monitoringEnabled = true;
driver.get("https://test-app.com");
performCriticalOperation();
monitoringEnabled = false;
// Clear logs after operation
devTools.send(domains.log().clear());Install with Tessl CLI
npx tessl i tessl/maven-org-seleniumhq-selenium--selenium-devtools-v102