Log Module
The Log module provides access to browser console logs and other logging events.
Overview
The Log module allows you to:
- Capture console log messages
- Monitor JavaScript errors
- Track different log levels
- Access log metadata
Accessing the Module
LogModule log = driver.Log;
Monitoring Console Logs
Basic Log Monitoring
// Add observer
driver.Log.OnEntryAdded.AddObserver((EntryAddedEventArgs e) =>
{
Console.WriteLine($"[{e.Level}] {e.Text}");
});
// Subscribe to events
SubscribeCommandParameters subscribe =
new SubscribeCommandParameters(driver.Log.OnEntryAdded.EventName);
await driver.Session.SubscribeAsync(subscribe);
// Navigate - console logs will be captured
await driver.BrowsingContext.NavigateAsync(
new NavigateCommandParameters(contextId, "https://example.com"));
Log Entry Properties
driver.Log.OnEntryAdded.AddObserver((EntryAddedEventArgs e) =>
{
Console.WriteLine($"Level: {e.Level}"); // Error, Warn, Info, Debug
Console.WriteLine($"Text: {e.Text}"); // Log message
Console.WriteLine($"Timestamp: {e.Timestamp}"); // When logged
Console.WriteLine($"Type: {e.Type}"); // "console", "javascript"
Console.WriteLine($"Method: {e.Method}"); // log, error, warn, etc.
// Source is always present; its BrowsingContextId may be null for
// realms not attached to a browsing context.
Console.WriteLine($"Source: {e.Source.RealmId}");
Console.WriteLine($"Context: {e.Source.BrowsingContextId}");
if (e.StackTrace != null)
{
Console.WriteLine("Stack trace:");
foreach (StackFrame frame in e.StackTrace.CallFrames)
{
Console.WriteLine($" {frame.FunctionName} at {frame.Url}:{frame.LineNumber}");
}
}
});
Filtering by Log Level
Monitor Only Errors
driver.Log.OnEntryAdded.AddObserver((EntryAddedEventArgs e) =>
{
if (e.Level == LogLevel.Error)
{
Console.WriteLine($"ERROR: {e.Text}");
if (e.StackTrace != null)
{
foreach (StackFrame frame in e.StackTrace.CallFrames)
{
Console.WriteLine($" at {frame.Url}:{frame.LineNumber}:{frame.ColumnNumber}");
}
}
}
});
Monitor Warnings and Errors
driver.Log.OnEntryAdded.AddObserver((EntryAddedEventArgs e) =>
{
if (e.Level == LogLevel.Error || e.Level == LogLevel.Warn)
{
Console.WriteLine($"[{e.Level}] {e.Text}");
}
});
Log Types
Console Logs
These come from console.log(), console.error(), etc.:
driver.Log.OnEntryAdded.AddObserver((EntryAddedEventArgs e) =>
{
if (e.Type == "console")
{
Console.WriteLine($"Console method: {e.Method}");
Console.WriteLine($"Args: {e.Arguments?.Count ?? 0}");
if (e.Arguments != null)
{
foreach (RemoteValue arg in e.Arguments)
{
Console.WriteLine($" Type: {arg.Type}");
Console.WriteLine($" Value: {(arg as ValueHoldingRemoteValue)?.ValueObject ?? "null"}");
}
}
}
});
JavaScript Errors
Uncaught JavaScript exceptions:
driver.Log.OnEntryAdded.AddObserver((EntryAddedEventArgs e) =>
{
if (e.Type == "javascript" && e.Level == LogLevel.Error)
{
Console.WriteLine($"JavaScript Error: {e.Text}");
}
});
Common Patterns
Collect All Logs
List<EntryAddedEventArgs> logs = new List<EntryAddedEventArgs>();
driver.Log.OnEntryAdded.AddObserver((EntryAddedEventArgs e) =>
{
logs.Add(e);
});
SubscribeCommandParameters subscribe =
new SubscribeCommandParameters(driver.Log.OnEntryAdded.EventName);
await driver.Session.SubscribeAsync(subscribe);
// Perform actions...
// Later, analyze logs
int errorCount = logs.Count(l => l.Level == LogLevel.Error);
int warnCount = logs.Count(l => l.Level == LogLevel.Warn);
Console.WriteLine($"Errors: {errorCount}, Warnings: {warnCount}");
Fail on JavaScript Errors
bool hasErrors = false;
driver.Log.OnEntryAdded.AddObserver((EntryAddedEventArgs e) =>
{
if (e.Type == "javascript" && e.Level == LogLevel.Error)
{
hasErrors = true;
Console.WriteLine($"JavaScript error detected: {e.Text}");
}
});
SubscribeCommandParameters subscribe =
new SubscribeCommandParameters(driver.Log.OnEntryAdded.EventName);
await driver.Session.SubscribeAsync(subscribe);
// Perform test actions...
await driver.BrowsingContext.NavigateAsync(navParams);
if (hasErrors)
{
throw new Exception("Test failed due to JavaScript errors");
}
Log to File
string logFilePath = "browser-console.log";
driver.Log.OnEntryAdded.AddObserver(async (EntryAddedEventArgs e) =>
{
string logLine = $"{e.Timestamp:yyyy-MM-dd HH:mm:ss.fff} [{e.Level}] {e.Text}\n";
await File.AppendAllTextAsync(logFilePath, logLine);
},
ObservableEventHandlerOptions.RunHandlerAsynchronously);
Best Practices
- Subscribe early: Subscribe to log events before navigating
- Filter appropriately: Don't process every log if you only need errors
- Handle async logging: Use async handlers if writing to files or databases
- Store important logs: Keep error logs for debugging
- Test for errors: Fail tests if unexpected JavaScript errors occur
Next Steps
- Events and Observables: Understanding event handling
- Examples: Console Monitoring: Complete examples
- API Reference: Complete API documentation