CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-seleniumhq-selenium--selenium-devtools-v99

Chrome DevTools Protocol version 99 support library for Selenium WebDriver Java bindings

Pending
Overview
Eval results
Files

logging.mddocs/

Log Management

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.

Capabilities

Log Handler

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;

Log Domain Control

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();

Log Event Monitoring

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();

Protocol Types

Log Entry

/**
 * 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 Integration

/**
 * 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();
}

Implementation Details

Level Conversion

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:

  • verboseLevel.FINEST
  • infoLevel.INFO
  • warningLevel.WARNING
  • errorLevel.SEVERE
  • unknown → Level.INFO (default)

Timestamp Conversion

/**
 * Convert CDP timestamp to milliseconds
 * @param timestamp - CDP timestamp
 * @return Milliseconds since epoch
 */
private long fromCdpTimestamp(Timestamp timestamp);

Usage Examples

Basic Log Monitoring

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");

Log Level Filtering

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);
    }
});

Source-Based Log Processing

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.
}

Log Collection and Analysis

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());
        });
    }
}

Log Clearing

// 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();

Integration with Selenium Logging

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);
}

Error Handling

Log management operations can encounter various issues:

  • Log domain not enabled: Enable log domain before monitoring
  • High log volume: Filter logs to prevent overwhelming the system
  • Memory issues: Large numbers of collected logs can consume memory
  • Timestamp parsing: Invalid timestamps fall back to current time

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
}

Performance Considerations

  • Log volume: High-frequency applications can generate many log entries
  • Memory usage: Collecting logs consumes memory; clear periodically if needed
  • Processing overhead: Log event handlers should be efficient
  • Network impact: Remote debugging increases log-related network traffic
  • Storage: Long-running tests may need log rotation or cleanup strategies

Install with Tessl CLI

npx tessl i tessl/maven-org-seleniumhq-selenium--selenium-devtools-v99

docs

events.md

index.md

javascript.md

logging.md

network.md

targets.md

tile.json