Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
ec94fd3
[java] Unify debug-logging switches into one real mechanism
MohabMohie Jul 29, 2026
ff32eab
[java][bidi][devtools] Raise the debug-logger switch from direct-cons…
MohabMohie Jul 29, 2026
a31a75a
[java][bidi][devtools] Document the debug-logging Connection construc…
MohabMohie Jul 29, 2026
4296a51
[java] Repair Debug's externally-removed handler; scope LoggingOption…
MohabMohie Jul 29, 2026
072512c
[java] Decide Debug's level raise off the effective level, not just i…
MohabMohie Jul 29, 2026
4d51cec
Merge branch 'trunk' into debug-logging-mechanism-stage1
MohabMohie Jul 29, 2026
c569d65
[java] Enforce, not just assert, the null-own-level precondition in t…
MohabMohie Jul 29, 2026
325168c
[java] Stop suppressing Selenium debug records from Grid's root handl…
MohabMohie Jul 29, 2026
d270074
[java] Assert the no-duplicate marker appears exactly once on stderr
MohabMohie Jul 29, 2026
59383f6
[java] Force the stubbed SE_DEBUG off before re-syncing Debug in cleanup
MohabMohie Jul 29, 2026
b35594b
Merge branch 'trunk' into debug-logging-mechanism-stage1
MohabMohie Jul 29, 2026
529bb21
Merge branch 'trunk' into debug-logging-mechanism-stage1
MohabMohie Jul 29, 2026
96ec9cf
Fix logging snapshot in RetryRequest: use live Debug.getDebugLogLevel…
MohabMohie Jul 29, 2026
ae54eb0
Move Debug.configureLogger() out of constructors' pre-validation path…
MohabMohie Jul 29, 2026
f9e03d9
Merge branch 'trunk' into debug-logging-mechanism-stage1
MohabMohie Jul 30, 2026
2f5c101
[java] Scope debug property to JUL diagnostics
MohabMohie Aug 1, 2026
1a69c0d
[java] Propagate requested debug level
MohabMohie Aug 1, 2026
65a4e4e
[java] Repair configured debug logger level
MohabMohie Aug 1, 2026
9b8a93e
[java] Restore repaired debug logger level
MohabMohie Aug 1, 2026
d536e3a
[java] Make debug handler inspection atomic
MohabMohie Aug 1, 2026
f87fd10
[java] Remove unused debug handler APIs
MohabMohie Aug 1, 2026
c7ba454
[java] Clarify debug logger configuration
MohabMohie Aug 3, 2026
7372c1e
[java] Clarify debug logger repair behavior
MohabMohie Aug 3, 2026
39d9bb9
Merge remote-tracking branch 'upstream/trunk' into debug-logging-mech…
MohabMohie Aug 12, 2026
888df9c
Narrow Java debug logging mechanism
MohabMohie Aug 12, 2026
6b4b204
Keep RetryRequest migration separate
MohabMohie Aug 12, 2026
5ed151e
Preserve more verbose debug handler levels
MohabMohie Aug 12, 2026
a503868
Harden debug handler repair
MohabMohie Aug 12, 2026
1c44aca
Remove stale handler before closing
MohabMohie Aug 12, 2026
6b5f663
Merge branch 'trunk' into debug-logging-mechanism-stage1
MohabMohie Aug 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 89 additions & 16 deletions java/src/org/openqa/selenium/internal/Debug.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,37 +17,50 @@

package org.openqa.selenium.internal;

import java.util.Arrays;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.ConsoleHandler;
import java.util.logging.Filter;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
import java.util.logging.StreamHandler;
import org.jspecify.annotations.Nullable;

/** Used to provide information about whether Selenium is running under debug mode. */
public class Debug {

private static final boolean IS_DEBUG;
private static final AtomicBoolean DEBUG_WARNING_LOGGED = new AtomicBoolean(false);
private static final Logger SELENIUM_LOGGER = Logger.getLogger("org.openqa.selenium");
private static boolean loggerConfigured = false;

static {
IS_DEBUG =
Boolean.getBoolean("selenium.debug") || Boolean.getBoolean("selenium.webdriver.verbose");
}
private static boolean loggerConfigured = false;
private static @Nullable Handler installedHandler;
private static @Nullable Level previousLevel;
private static @Nullable Level levelSetByDebug;

private Debug() {
// Utility class
}

/** Returns whether either Selenium debug system property is currently enabled. */
public static boolean isDebugging() {
return IS_DEBUG;
return Boolean.getBoolean("selenium.debug") || Boolean.getBoolean("selenium.webdriver.verbose");
}
Comment thread
MohabMohie marked this conversation as resolved.

/**
* Returns the legacy level selected by the current debug system properties.
*
* @deprecated Log at a fixed severity and use {@link #configureLogger()} to expose debug output.
*/
@Deprecated(forRemoval = true)
public static Level getDebugLogLevel() {
return isDebugging() ? Level.INFO : Level.FINE;
}

static synchronized boolean isHandlerCurrentlyInstalled() {
return installedHandler != null
&& Arrays.asList(SELENIUM_LOGGER.getHandlers()).contains(installedHandler);
}

public static boolean isDebugAll() {
boolean everything = Boolean.parseBoolean(System.getenv("SE_DEBUG"));
if (everything && DEBUG_WARNING_LOGGED.compareAndSet(false, true)) {
Expand All @@ -59,16 +72,76 @@ public static boolean isDebugAll() {
return everything;
}

public static void configureLogger() {
if (!isDebugAll() || loggerConfigured) {
private static Level effectiveLevel(Logger logger) {
for (Logger current = logger; current != null; current = current.getParent()) {
Level level = current.getLevel();
if (level != null) {
return level;
}
}
return Level.INFO;
}

/**
* Applies the current Selenium debug switches to the {@code org.openqa.selenium} logger. Selenium
* owns the added handler and restores only logger state that it changed. Repeated calls also
* repair an externally removed handler or a less-verbose logger level.
*/
public static synchronized void configureLogger() {
boolean shouldDebug = isDebugAll() || isDebugging();
Handler currentHandler = installedHandler;
boolean handlerInstalled =
currentHandler != null
&& Arrays.asList(SELENIUM_LOGGER.getHandlers()).contains(currentHandler);
Level currentEffectiveLevel = effectiveLevel(SELENIUM_LOGGER);
if (shouldDebug == loggerConfigured
&& (!shouldDebug
|| (handlerInstalled
&& currentHandler != null
&& currentEffectiveLevel.intValue() <= Level.FINE.intValue()
&& currentHandler.getLevel().intValue() <= currentEffectiveLevel.intValue()))) {
return;
}
Comment thread
qodo-code-review[bot] marked this conversation as resolved.

SELENIUM_LOGGER.setLevel(Level.FINE);
if (shouldDebug) {
if (!loggerConfigured) {
previousLevel = SELENIUM_LOGGER.getLevel();
levelSetByDebug = null;
}

if (currentEffectiveLevel.intValue() > Level.FINE.intValue()) {
SELENIUM_LOGGER.setLevel(Level.FINE);
levelSetByDebug = Level.FINE;
currentEffectiveLevel = Level.FINE;
}

if (handlerInstalled && currentHandler != null) {
currentHandler.setLevel(currentEffectiveLevel);
} else {
if (currentHandler != null) {
SELENIUM_LOGGER.removeHandler(currentHandler);
currentHandler.close();
Comment thread
qodo-code-review[bot] marked this conversation as resolved.
}
Handler handler = new ConsoleHandler();
handler.setLevel(currentEffectiveLevel);
Filter belowInfo = record -> record.getLevel().intValue() < Level.INFO.intValue();
Comment thread
qodo-code-review[bot] marked this conversation as resolved.
handler.setFilter(belowInfo);
SELENIUM_LOGGER.addHandler(handler);
installedHandler = handler;
}
} else {
if (currentHandler != null) {
SELENIUM_LOGGER.removeHandler(currentHandler);
currentHandler.close();
installedHandler = null;
}
if (levelSetByDebug != null && levelSetByDebug.equals(SELENIUM_LOGGER.getLevel())) {
SELENIUM_LOGGER.setLevel(previousLevel);
}
previousLevel = null;
levelSetByDebug = null;
}

StreamHandler handler = new StreamHandler(System.err, new SimpleFormatter());
handler.setLevel(Level.FINE);
SELENIUM_LOGGER.addHandler(handler);
loggerConfigured = true;
loggerConfigured = shouldDebug;
}
}
4 changes: 3 additions & 1 deletion java/src/org/openqa/selenium/remote/RemoteWebDriver.java
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,9 @@ public class RemoteWebDriver
PrintsPage,
TakesScreenshot {

// Configure before subclass constructor arguments can trigger driver discovery logs.
static {
org.openqa.selenium.internal.Debug.configureLogger();
Debug.configureLogger();
}

private static final Logger LOG = Logger.getLogger(RemoteWebDriver.class.getName());
Expand Down Expand Up @@ -207,6 +208,7 @@ public RemoteWebDriver(
CommandExecutor executor, Capabilities capabilities, ClientConfig clientConfig) {
this.clientConfig = Require.nonNull("Client config", clientConfig);
this.executor = Require.nonNull("Command executor", executor);
Debug.configureLogger();
this.capabilities = requireNonNullElseGet(capabilities, () -> new ImmutableCapabilities());

try {
Expand Down
2 changes: 2 additions & 0 deletions java/test/org/openqa/selenium/internal/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,7 @@ java_test_suite(
"//java/src/org/openqa/selenium:core",
artifact("org.assertj:assertj-core"),
artifact("org.junit.jupiter:junit-jupiter-api"),
artifact("uk.org.webcompere:system-stubs-core"),
artifact("uk.org.webcompere:system-stubs-jupiter"),
] + JUNIT5_DEPS,
)
Loading