Console and logs
Something went wrong, and the only evidence is a failed assertion. There are three separate streams of information that could explain it: what the page wrote to the browser console, what exception JavaScript threw, and what Selenium itself was sending to and receiving from the driver. By default you see none of them.
Recommended approach
Browser console and JavaScript errors. With WebDriver BiDi enabled, the log module streams console entries and uncaught JavaScript exceptions to your test as they happen. Register a handler before the action you want to observe, then assert on the entries it collects. This is the cross-browser, standards-based replacement for the old Chromium-only log retrieval, and it catches errors the page swallowed before a user would have seen them.
Selenium’s own logging. Each binding logs through its language’s standard logging
facility: java.util.logging in Java, the logging module in Python, Selenium’s Log class
in .NET, and Selenium::WebDriver.logger in Ruby. Raising the level to debug shows every
command sent to the driver and every response, which is usually enough to tell whether the
problem is in your code, the driver or the browser. Logs go to the console by default; add a
file handler to keep them with the rest of your test artifacts.
Driver logs. The browser driver (chromedriver, geckodriver, and so on) keeps its own log, configured through the driver’s service class. Reach for it when the browser fails to start or crashes mid-session.
Collect console messages with BiDi:
@Test
void testListenToConsoleLog() throws ExecutionException, InterruptedException, TimeoutException {
try (LogInspector logInspector = new LogInspector(driver)) {
CompletableFuture<ConsoleLogEntry> future = new CompletableFuture<>();
logInspector.onConsoleEntry(future::complete);
driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");
driver.findElement(By.id("consoleLog")).click();
ConsoleLogEntry logEntry = future.get(5, TimeUnit.SECONDS);/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/LogTest.java
package dev.selenium.bidirectional.webdriver_bidi;
import dev.selenium.BaseTest;
import java.time.Duration;
import java.util.concurrent.*;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.bidi.module.LogInspector;
import org.openqa.selenium.bidi.log.ConsoleLogEntry;
import org.openqa.selenium.bidi.log.JavascriptLogEntry;
import org.openqa.selenium.bidi.log.LogLevel;
import org.openqa.selenium.bidi.log.StackTrace;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.support.ui.WebDriverWait;
class LogTest extends BaseTest {
@BeforeEach
public void setup() {
FirefoxOptions options = new FirefoxOptions();
options.setCapability("webSocketUrl", true);
driver = new FirefoxDriver(options);
}
@Test
void testListenToConsoleLog() throws ExecutionException, InterruptedException, TimeoutException {
try (LogInspector logInspector = new LogInspector(driver)) {
CompletableFuture<ConsoleLogEntry> future = new CompletableFuture<>();
logInspector.onConsoleEntry(future::complete);
driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");
driver.findElement(By.id("consoleLog")).click();
ConsoleLogEntry logEntry = future.get(5, TimeUnit.SECONDS);
Assertions.assertEquals("Hello, world!", logEntry.getText());
Assertions.assertEquals(1, logEntry.getArgs().size());
Assertions.assertEquals("console", logEntry.getType());
Assertions.assertEquals("log", logEntry.getMethod());
Assertions.assertNull(logEntry.getStackTrace());
}
}
@Test
void testListenToJavascriptLog()
throws ExecutionException, InterruptedException, TimeoutException {
try (LogInspector logInspector = new LogInspector(driver)) {
CompletableFuture<JavascriptLogEntry> future = new CompletableFuture<>();
logInspector.onJavaScriptLog(future::complete);
driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");
driver.findElement(By.id("jsException")).click();
JavascriptLogEntry logEntry = future.get(5, TimeUnit.SECONDS);
Assertions.assertEquals("Error: Not working", logEntry.getText());
Assertions.assertEquals("javascript", logEntry.getType());
Assertions.assertEquals(LogLevel.ERROR, logEntry.getLevel());
}
}
@Test
void testListenToJavascriptErrorLog()
throws ExecutionException, InterruptedException, TimeoutException {
try (LogInspector logInspector = new LogInspector(driver)) {
CompletableFuture<JavascriptLogEntry> future = new CompletableFuture<>();
logInspector.onJavaScriptException(future::complete);
driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");
driver.findElement(By.id("jsException")).click();
JavascriptLogEntry logEntry = future.get(5, TimeUnit.SECONDS);
Assertions.assertEquals("Error: Not working", logEntry.getText());
Assertions.assertEquals("javascript", logEntry.getType());
}
}
@Test
void testRetrieveStacktraceForALog()
throws ExecutionException, InterruptedException, TimeoutException {
try (LogInspector logInspector = new LogInspector(driver)) {
CompletableFuture<JavascriptLogEntry> future = new CompletableFuture<>();
logInspector.onJavaScriptException(future::complete);
driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");
driver.findElement(By.id("logWithStacktrace")).click();
JavascriptLogEntry logEntry = future.get(5, TimeUnit.SECONDS);
StackTrace stackTrace = logEntry.getStackTrace();
Assertions.assertNotNull(stackTrace);
Assertions.assertEquals(4, stackTrace.getCallFrames().size());
}
}
@Test
void testListenToLogsWithMultipleConsumers()
throws ExecutionException, InterruptedException, TimeoutException {
try (LogInspector logInspector = new LogInspector(driver)) {
CompletableFuture<JavascriptLogEntry> completableFuture1 = new CompletableFuture<>();
logInspector.onJavaScriptLog(completableFuture1::complete);
CompletableFuture<JavascriptLogEntry> completableFuture2 = new CompletableFuture<>();
logInspector.onJavaScriptLog(completableFuture2::complete);
driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");
driver.findElement(By.id("jsException")).click();
JavascriptLogEntry logEntry = completableFuture1.get(5, TimeUnit.SECONDS);
Assertions.assertEquals("Error: Not working", logEntry.getText());
Assertions.assertEquals("javascript", logEntry.getType());
logEntry = completableFuture2.get(5, TimeUnit.SECONDS);
Assertions.assertEquals("Error: Not working", logEntry.getText());
Assertions.assertEquals("javascript", logEntry.getType());
}
}
}
driver.script.add_console_message_handler(log_entries.append)
driver.find_element(By.ID, "consoleLog").click()
WebDriverWait(driver, 5).until(lambda _: log_entries)
assert log_entries[0].text == "Hello, world!"/examples/python/tests/bidi/test_bidi_logging.py
import pytest
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
@pytest.mark.driver_type("bidi")
def test_add_console_log_handler(driver):
driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
log_entries = []
driver.script.add_console_message_handler(log_entries.append)
driver.find_element(By.ID, "consoleLog").click()
WebDriverWait(driver, 5).until(lambda _: log_entries)
assert log_entries[0].text == "Hello, world!"
@pytest.mark.driver_type("bidi")
def test_remove_console_log_handler(driver):
driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
log_entries = []
id = driver.script.add_console_message_handler(log_entries.append)
driver.script.remove_console_message_handler(id)
driver.find_element(By.ID, "consoleLog").click()
assert len(log_entries) == 0
@pytest.mark.driver_type("bidi")
def test_add_js_exception_handler(driver):
driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
log_entries = []
driver.script.add_javascript_error_handler(log_entries.append)
driver.find_element(By.ID, "jsException").click()
WebDriverWait(driver, 5).until(lambda _: log_entries)
assert log_entries[0].text == "Error: Not working"
@pytest.mark.driver_type("bidi")
def test_remove_js_exception_handler(driver):
driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
log_entries = []
id = driver.script.add_javascript_error_handler(log_entries.append)
driver.script.remove_javascript_error_handler(id)
driver.find_element(By.ID, "consoleLog").click()
assert len(log_entries) == 0
const inspector = await LogInspector(driver)
await inspector.onConsoleEntry(function (log) {
logEntry = log
})
await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
await driver.findElement({id: 'consoleLog'}).click()
assert.equal(logEntry.text, 'Hello, world!')/examples/javascript/test/bidirectional/logInspector.spec.js
const assert = require("assert");
const firefox = require('selenium-webdriver/firefox');
const LogInspector = require('selenium-webdriver/bidi/logInspector');
const {Builder} = require("selenium-webdriver");
describe('Log Inspector', function () {
let driver
beforeEach(async function () {
driver = new Builder()
.forBrowser('firefox')
.setFirefoxOptions(new firefox.Options().enableBidi())
.build()
})
afterEach(async function () {
await driver.quit()
})
it('test listen to console log', async function () {
let logEntry = null
const inspector = await LogInspector(driver)
await inspector.onConsoleEntry(function (log) {
logEntry = log
})
await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
await driver.findElement({id: 'consoleLog'}).click()
assert.equal(logEntry.text, 'Hello, world!')
assert.equal(logEntry.realm, null)
assert.equal(logEntry.type, 'console')
assert.equal(logEntry.level, 'info')
assert.equal(logEntry.method, 'log')
assert.equal(logEntry.stackTrace, null)
assert.equal(logEntry.args.length, 1)
await inspector.close()
})
it('test listen to javascript error log', async function () {
let logEntry = null
const inspector = await LogInspector(driver)
await inspector.onJavascriptException(function (log) {
logEntry = log
})
await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
await driver.findElement({id: 'jsException'}).click()
assert.equal(logEntry.text, 'Error: Not working')
assert.equal(logEntry.type, 'javascript')
assert.equal(logEntry.level, 'error')
await inspector.close()
})
it('test retrieve stack trace for a log', async function () {
let logEntry = null
const inspector = await LogInspector(driver)
await inspector.onJavascriptException(function (log) {
logEntry = log
})
await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
await driver.findElement({id: 'jsException'}).click()
const stackTrace = logEntry.stackTrace
assert.notEqual(stackTrace, null)
assert.equal(stackTrace.callFrames.length, 3)
await inspector.close()
})
it('test listen to logs with multiple consumers', async function () {
let logEntry1 = null
let logEntry2 = null
const inspector = await LogInspector(driver)
await inspector.onJavascriptException(function (log) {
logEntry1 = log
})
await inspector.onJavascriptException(function (log) {
logEntry2 = log
})
await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
await driver.findElement({id: 'jsException'}).click()
assert.equal(logEntry1.text, 'Error: Not working')
assert.equal(logEntry1.type, 'javascript')
assert.equal(logEntry1.level, 'error')
assert.equal(logEntry2.text, 'Error: Not working')
assert.equal(logEntry2.type, 'javascript')
assert.equal(logEntry2.level, 'error')
await inspector.close()
})
})Collect JavaScript exceptions with BiDi:
driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");
driver.findElement(By.id("jsException")).click();
JavascriptLogEntry logEntry = future.get(5, TimeUnit.SECONDS);
/examples/java/src/test/java/dev/selenium/bidirectional/webdriver_bidi/LogTest.java
package dev.selenium.bidirectional.webdriver_bidi;
import dev.selenium.BaseTest;
import java.time.Duration;
import java.util.concurrent.*;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.bidi.module.LogInspector;
import org.openqa.selenium.bidi.log.ConsoleLogEntry;
import org.openqa.selenium.bidi.log.JavascriptLogEntry;
import org.openqa.selenium.bidi.log.LogLevel;
import org.openqa.selenium.bidi.log.StackTrace;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.support.ui.WebDriverWait;
class LogTest extends BaseTest {
@BeforeEach
public void setup() {
FirefoxOptions options = new FirefoxOptions();
options.setCapability("webSocketUrl", true);
driver = new FirefoxDriver(options);
}
@Test
void testListenToConsoleLog() throws ExecutionException, InterruptedException, TimeoutException {
try (LogInspector logInspector = new LogInspector(driver)) {
CompletableFuture<ConsoleLogEntry> future = new CompletableFuture<>();
logInspector.onConsoleEntry(future::complete);
driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");
driver.findElement(By.id("consoleLog")).click();
ConsoleLogEntry logEntry = future.get(5, TimeUnit.SECONDS);
Assertions.assertEquals("Hello, world!", logEntry.getText());
Assertions.assertEquals(1, logEntry.getArgs().size());
Assertions.assertEquals("console", logEntry.getType());
Assertions.assertEquals("log", logEntry.getMethod());
Assertions.assertNull(logEntry.getStackTrace());
}
}
@Test
void testListenToJavascriptLog()
throws ExecutionException, InterruptedException, TimeoutException {
try (LogInspector logInspector = new LogInspector(driver)) {
CompletableFuture<JavascriptLogEntry> future = new CompletableFuture<>();
logInspector.onJavaScriptLog(future::complete);
driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");
driver.findElement(By.id("jsException")).click();
JavascriptLogEntry logEntry = future.get(5, TimeUnit.SECONDS);
Assertions.assertEquals("Error: Not working", logEntry.getText());
Assertions.assertEquals("javascript", logEntry.getType());
Assertions.assertEquals(LogLevel.ERROR, logEntry.getLevel());
}
}
@Test
void testListenToJavascriptErrorLog()
throws ExecutionException, InterruptedException, TimeoutException {
try (LogInspector logInspector = new LogInspector(driver)) {
CompletableFuture<JavascriptLogEntry> future = new CompletableFuture<>();
logInspector.onJavaScriptException(future::complete);
driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");
driver.findElement(By.id("jsException")).click();
JavascriptLogEntry logEntry = future.get(5, TimeUnit.SECONDS);
Assertions.assertEquals("Error: Not working", logEntry.getText());
Assertions.assertEquals("javascript", logEntry.getType());
}
}
@Test
void testRetrieveStacktraceForALog()
throws ExecutionException, InterruptedException, TimeoutException {
try (LogInspector logInspector = new LogInspector(driver)) {
CompletableFuture<JavascriptLogEntry> future = new CompletableFuture<>();
logInspector.onJavaScriptException(future::complete);
driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");
driver.findElement(By.id("logWithStacktrace")).click();
JavascriptLogEntry logEntry = future.get(5, TimeUnit.SECONDS);
StackTrace stackTrace = logEntry.getStackTrace();
Assertions.assertNotNull(stackTrace);
Assertions.assertEquals(4, stackTrace.getCallFrames().size());
}
}
@Test
void testListenToLogsWithMultipleConsumers()
throws ExecutionException, InterruptedException, TimeoutException {
try (LogInspector logInspector = new LogInspector(driver)) {
CompletableFuture<JavascriptLogEntry> completableFuture1 = new CompletableFuture<>();
logInspector.onJavaScriptLog(completableFuture1::complete);
CompletableFuture<JavascriptLogEntry> completableFuture2 = new CompletableFuture<>();
logInspector.onJavaScriptLog(completableFuture2::complete);
driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");
driver.findElement(By.id("jsException")).click();
JavascriptLogEntry logEntry = completableFuture1.get(5, TimeUnit.SECONDS);
Assertions.assertEquals("Error: Not working", logEntry.getText());
Assertions.assertEquals("javascript", logEntry.getType());
logEntry = completableFuture2.get(5, TimeUnit.SECONDS);
Assertions.assertEquals("Error: Not working", logEntry.getText());
Assertions.assertEquals("javascript", logEntry.getType());
}
}
}
driver.script.add_javascript_error_handler(log_entries.append)
driver.find_element(By.ID, "jsException").click()
WebDriverWait(driver, 5).until(lambda _: log_entries)
assert log_entries[0].text == "Error: Not working"/examples/python/tests/bidi/test_bidi_logging.py
import pytest
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
@pytest.mark.driver_type("bidi")
def test_add_console_log_handler(driver):
driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
log_entries = []
driver.script.add_console_message_handler(log_entries.append)
driver.find_element(By.ID, "consoleLog").click()
WebDriverWait(driver, 5).until(lambda _: log_entries)
assert log_entries[0].text == "Hello, world!"
@pytest.mark.driver_type("bidi")
def test_remove_console_log_handler(driver):
driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
log_entries = []
id = driver.script.add_console_message_handler(log_entries.append)
driver.script.remove_console_message_handler(id)
driver.find_element(By.ID, "consoleLog").click()
assert len(log_entries) == 0
@pytest.mark.driver_type("bidi")
def test_add_js_exception_handler(driver):
driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
log_entries = []
driver.script.add_javascript_error_handler(log_entries.append)
driver.find_element(By.ID, "jsException").click()
WebDriverWait(driver, 5).until(lambda _: log_entries)
assert log_entries[0].text == "Error: Not working"
@pytest.mark.driver_type("bidi")
def test_remove_js_exception_handler(driver):
driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
log_entries = []
id = driver.script.add_javascript_error_handler(log_entries.append)
driver.script.remove_javascript_error_handler(id)
driver.find_element(By.ID, "consoleLog").click()
assert len(log_entries) == 0
const inspector = await LogInspector(driver)
await inspector.onJavascriptException(function (log) {
logEntry = log
})
await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
await driver.findElement({id: 'jsException'}).click()
assert.equal(logEntry.text, 'Error: Not working')/examples/javascript/test/bidirectional/logInspector.spec.js
const assert = require("assert");
const firefox = require('selenium-webdriver/firefox');
const LogInspector = require('selenium-webdriver/bidi/logInspector');
const {Builder} = require("selenium-webdriver");
describe('Log Inspector', function () {
let driver
beforeEach(async function () {
driver = new Builder()
.forBrowser('firefox')
.setFirefoxOptions(new firefox.Options().enableBidi())
.build()
})
afterEach(async function () {
await driver.quit()
})
it('test listen to console log', async function () {
let logEntry = null
const inspector = await LogInspector(driver)
await inspector.onConsoleEntry(function (log) {
logEntry = log
})
await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
await driver.findElement({id: 'consoleLog'}).click()
assert.equal(logEntry.text, 'Hello, world!')
assert.equal(logEntry.realm, null)
assert.equal(logEntry.type, 'console')
assert.equal(logEntry.level, 'info')
assert.equal(logEntry.method, 'log')
assert.equal(logEntry.stackTrace, null)
assert.equal(logEntry.args.length, 1)
await inspector.close()
})
it('test listen to javascript error log', async function () {
let logEntry = null
const inspector = await LogInspector(driver)
await inspector.onJavascriptException(function (log) {
logEntry = log
})
await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
await driver.findElement({id: 'jsException'}).click()
assert.equal(logEntry.text, 'Error: Not working')
assert.equal(logEntry.type, 'javascript')
assert.equal(logEntry.level, 'error')
await inspector.close()
})
it('test retrieve stack trace for a log', async function () {
let logEntry = null
const inspector = await LogInspector(driver)
await inspector.onJavascriptException(function (log) {
logEntry = log
})
await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
await driver.findElement({id: 'jsException'}).click()
const stackTrace = logEntry.stackTrace
assert.notEqual(stackTrace, null)
assert.equal(stackTrace.callFrames.length, 3)
await inspector.close()
})
it('test listen to logs with multiple consumers', async function () {
let logEntry1 = null
let logEntry2 = null
const inspector = await LogInspector(driver)
await inspector.onJavascriptException(function (log) {
logEntry1 = log
})
await inspector.onJavascriptException(function (log) {
logEntry2 = log
})
await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
await driver.findElement({id: 'jsException'}).click()
assert.equal(logEntry1.text, 'Error: Not working')
assert.equal(logEntry1.type, 'javascript')
assert.equal(logEntry1.level, 'error')
assert.equal(logEntry2.text, 'Error: Not working')
assert.equal(logEntry2.type, 'javascript')
assert.equal(logEntry2.level, 'error')
await inspector.close()
})
})Turn up Selenium’s own logging:
Logger logger = Logger.getLogger("");
logger.setLevel(Level.FINE);
Arrays.stream(logger.getHandlers()).forEach(handler -> {
handler.setLevel(Level.FINE);/examples/java/src/test/java/dev/selenium/troubleshooting/LoggingTest.java
package dev.selenium.troubleshooting;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.logging.FileHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
import dev.selenium.BaseTest;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.manager.SeleniumManager;
import org.openqa.selenium.remote.RemoteWebDriver;
public class LoggingTest extends BaseTest {
@AfterEach
public void loggingOff() {
Logger logger = Logger.getLogger("");
logger.setLevel(Level.INFO);
Arrays.stream(logger.getHandlers()).forEach(handler -> {
handler.setLevel(Level.INFO);
});
}
@Test
public void logging() throws IOException {
Logger logger = Logger.getLogger("");
logger.setLevel(Level.FINE);
Arrays.stream(logger.getHandlers()).forEach(handler -> {
handler.setLevel(Level.FINE);
});
Path output = artifactsDir().resolve("selenium.xml");
Handler handler = new FileHandler(output.toString());
logger.addHandler(handler);
Logger.getLogger(RemoteWebDriver.class.getName()).setLevel(Level.FINEST);
Logger.getLogger(SeleniumManager.class.getName()).setLevel(Level.SEVERE);
Logger localLogger = Logger.getLogger(this.getClass().getName());
localLogger.warning("this is a warning");
localLogger.info("this is useful information");
localLogger.fine("this is detailed debug information");
byte[] bytes = Files.readAllBytes(output);
String fileContent = new String(bytes);
Assertions.assertTrue(fileContent.contains("this is a warning"));
Assertions.assertTrue(fileContent.contains("this is useful information"));
Assertions.assertTrue(fileContent.contains("this is detailed debug information"));
}
}
logger = logging.getLogger('selenium')
logger.setLevel(logging.DEBUG)/examples/python/tests/troubleshooting/test_logging.py
import logging
def test_logging(log_path):
logger = logging.getLogger('selenium')
logger.setLevel(logging.DEBUG)
handler = logging.FileHandler(log_path)
logger.addHandler(handler)
logging.getLogger('selenium.webdriver.remote').setLevel(logging.WARN)
logging.getLogger('selenium.webdriver.common').setLevel(logging.DEBUG)
logger.info("this is useful information")
logger.warning("this is a warning")
logger.debug("this is detailed debug information")
with open(log_path, 'r') as fp:
assert len(fp.readlines()) == 3
Log.SetLevel(LogEventLevel.Trace);/examples/dotnet/SeleniumDocs/Troubleshooting/LoggingTest.cs
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.Internal.Logging;
using OpenQA.Selenium.Manager;
using OpenQA.Selenium.Remote;
using System;
using System.IO;
namespace SeleniumDocs.Troubleshooting
{
[TestClass]
public class LoggingTest
{
private const string filePath = "Selenium.log";
[TestMethod]
public void Logging()
{
Log.SetLevel(LogEventLevel.Trace);
Log.Handlers.Add(new FileLogHandler(filePath));
Log.SetLevel(typeof(RemoteWebDriver), LogEventLevel.Debug);
Log.SetLevel(typeof(SeleniumManager), LogEventLevel.Info);
Warn("this is a warning");
Info("this is useful information");
Debug("this is detailed debug information");
using (var fileStream = File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
using (var streamReader = new StreamReader(fileStream))
{
var fileLogContent = streamReader.ReadToEnd();
StringAssert.Contains(fileLogContent, "this is a warning");
StringAssert.Contains(fileLogContent, "this is useful information");
StringAssert.Contains(fileLogContent, "this is detailed debug information");
}
}
}
[TestCleanup]
public void TestCleanup()
{
// reset log to default
Log.SetLevel(LogEventLevel.Info)
.Handlers.Clear()
.Handlers.Add(new TextWriterHandler(Console.Error));
}
// logging is only for internal usage
// hacking it via reflection
private void Debug(string message)
{
LogMessage("Debug", message);
}
private void Warn(string message)
{
LogMessage("Warn", message);
}
private void Info(string message)
{
LogMessage("Info", message);
}
private void LogMessage(string methodName, string message)
{
var getLoggerMethod = typeof(Log).GetMethod("GetLogger", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic, new Type[] { typeof(Type) });
var logger = getLoggerMethod.Invoke(null, new object[] { typeof(LoggingTest) });
var emitMethod = logger.GetType().GetMethod(methodName);
emitMethod.Invoke(logger, new object[] { message });
}
}
}
logger = Selenium::WebDriver.logger
logger.level = :debug/examples/ruby/spec/troubleshooting/logging_spec.rb
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Logging' do
let(:file_name) { Tempfile.new('logging').path }
after { FileUtils.rm_f(file_name) }
it 'logs things' do
logger = Selenium::WebDriver.logger
logger.level = :debug
logger.output = file_name
logger.ignore(:jwp_caps, :logger_info)
logger.allow(%i[selenium_manager example_id])
logger.warn('this is a warning', id: :example_id)
logger.info('this is useful information', id: :example_id)
logger.debug('this is detailed debug information', id: :example_id)
expect(File.readlines(file_name).grep(/\[:example_id\]/).size).to eq 3
end
end
Common errors
- JavascriptException: a script you executed through WebDriver threw. The BiDi log module shows the page’s own errors, which this exception does not cover.
- UnsupportedCommandException: BiDi was not enabled for the session, so the log module is unavailable.
Reference
- BiDi log: console entries and JavaScript exceptions
- Logging Selenium commands: levels, output and filtering per binding
- Driver service: where the driver’s own log goes
- Enabling BiDi



