CtrlK
BlogDocsLog inGet started
Tessl Logo

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

Java bindings for Chrome DevTools Protocol version 102, providing programmatic access to Chrome browser debugging and automation capabilities

Pending
Overview
Eval results
Files

console-logging.mddocs/

Console Log Management

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.

Capabilities

V102Log Class

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:

Basic Log Monitoring

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

Log Level Filtering

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

Log Collection and Analysis

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

Source-Based Log Filtering

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

Log Level Conversion

The V102Log class provides automatic conversion between CDP log levels and Java logging levels:

CDP to Java Level Mapping

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

Timestamp Handling

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

CDP Protocol Classes

The V102Log class interacts with generated CDP protocol classes:

Log Domain

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

Selenium Integration Types

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

Event Processing Flow

The log processing follows this flow:

  1. CDP Log Entry: Browser generates log entry with CDP-specific format
  2. Event Notification: V102Log receives CDP LogEntry via entryAdded event
  3. Level Conversion: CDP level converted to Java logging Level
  4. Timestamp Conversion: CDP timestamp converted to milliseconds
  5. Idealized Entry: Creates Selenium idealized LogEntry
  6. Event Dispatch: Dispatches converted entry to listeners

Advanced Log Management Patterns

Log Buffering

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

Log Persistence

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

Conditional Log Monitoring

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

docs

console-logging.md

domain-management.md

index.md

javascript-execution.md

network-operations.md

runtime-events.md

target-management.md

tile.json