Skip to content

Commit c2e76c5

Browse files
committed
Attempt to reduce log output to just failing tests
1 parent 26efaf6 commit c2e76c5

File tree

6 files changed

+215
-3
lines changed

6 files changed

+215
-3
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Licensed to the Software Freedom Conservancy (SFC) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The SFC licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package org.openqa.selenium.build;
19+
20+
import java.lang.management.ManagementFactory;
21+
22+
public class Debug {
23+
24+
private static boolean COMMAND_LINE_DEBUG = ManagementFactory.getRuntimeMXBean().getInputArguments().stream()
25+
.map(str -> str.contains("-agentlib:jdwp"))
26+
.reduce(Boolean::logicalOr)
27+
.orElse(false);
28+
private static boolean PROPERTY_DEBUG = Boolean.getBoolean("selenium.debug");
29+
30+
private Debug() {
31+
// Utility class
32+
}
33+
34+
public static boolean isDebug() {
35+
return COMMAND_LINE_DEBUG || PROPERTY_DEBUG;
36+
}
37+
}

java/client/test/org/openqa/selenium/testing/BUILD.bazel

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ java_library(
2828
name = "test-base",
2929
testonly = True,
3030
srcs = [
31+
"CaptureLoggingRule.java",
3132
"IgnoreComparator.java",
3233
"JUnit4TestBase.java",
3334
"Pages.java",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
// Licensed to the Software Freedom Conservancy (SFC) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The SFC licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package org.openqa.selenium.testing;
19+
20+
import org.junit.rules.TestRule;
21+
import org.junit.runner.Description;
22+
import org.junit.runners.model.Statement;
23+
24+
import java.io.PrintWriter;
25+
import java.io.StringWriter;
26+
import java.time.Instant;
27+
import java.time.LocalDateTime;
28+
import java.time.ZoneId;
29+
import java.time.format.DateTimeFormatter;
30+
import java.util.ArrayList;
31+
import java.util.Arrays;
32+
import java.util.List;
33+
import java.util.logging.ConsoleHandler;
34+
import java.util.logging.Formatter;
35+
import java.util.logging.Handler;
36+
import java.util.logging.LogManager;
37+
import java.util.logging.LogRecord;
38+
import java.util.logging.Logger;
39+
40+
import static java.util.Collections.emptyList;
41+
import static java.util.stream.Collectors.toList;
42+
import static org.openqa.selenium.build.Debug.isDebug;
43+
44+
public class CaptureLoggingRule implements TestRule {
45+
@Override
46+
public Statement apply(Statement statement, Description description) {
47+
return new CaptureLoggingStatement(statement);
48+
}
49+
50+
private static class CaptureLoggingStatement extends Statement {
51+
52+
private final Statement statement;
53+
54+
public CaptureLoggingStatement(Statement statement) {
55+
this.statement = statement;
56+
}
57+
58+
@Override
59+
public void evaluate() throws Throwable {
60+
List<Handler> handlers = beginLogCapture();
61+
62+
try {
63+
statement.evaluate();
64+
} catch (Throwable throwable) {
65+
writeCapturedLogs();
66+
throw throwable;
67+
} finally {
68+
endLogCapture(handlers);
69+
}
70+
71+
}
72+
73+
private List<Handler> beginLogCapture() {
74+
if (isDebug()) {
75+
return emptyList();
76+
}
77+
78+
Logger logger = LogManager.getLogManager().getLogger("");
79+
80+
// Capture the original log handlers
81+
List<Handler> originalHandlers = Arrays.stream(logger.getHandlers())
82+
.filter(handler -> handler instanceof ConsoleHandler)
83+
.collect(toList());
84+
85+
// Remove them from the logger
86+
originalHandlers.forEach(logger::removeHandler);
87+
88+
// Replace them with log handlers that record messages
89+
logger.addHandler(new RecordingHandler());
90+
91+
return originalHandlers;
92+
}
93+
94+
private void writeCapturedLogs() {
95+
if (isDebug()) {
96+
return;
97+
}
98+
99+
Logger logger = LogManager.getLogManager().getLogger("");
100+
Arrays.stream(logger.getHandlers())
101+
.filter(handler -> handler instanceof RecordingHandler)
102+
.map(handler -> (RecordingHandler) handler)
103+
.forEach(RecordingHandler::write);
104+
}
105+
106+
private void endLogCapture(List<Handler> handlers) {
107+
if (isDebug()) {
108+
return;
109+
}
110+
111+
// Find our recording handler
112+
Logger logger = LogManager.getLogManager().getLogger("");
113+
List<RecordingHandler> recordingHandlers = Arrays.stream(logger.getHandlers())
114+
.filter(handler -> handler instanceof RecordingHandler)
115+
.map(handler -> (RecordingHandler) handler)
116+
.collect(toList());
117+
118+
recordingHandlers.forEach(logger::removeHandler);
119+
handlers.forEach(logger::addHandler);
120+
}
121+
}
122+
123+
private static class RecordingHandler extends Handler {
124+
125+
private final List<LogRecord> records = new ArrayList<>();
126+
127+
@Override
128+
public void publish(LogRecord record) {
129+
records.add(record);
130+
}
131+
132+
@Override
133+
public void flush() {
134+
// no-op
135+
}
136+
137+
@Override
138+
public void close() throws SecurityException {
139+
// no-op
140+
}
141+
142+
public void write() {
143+
Formatter formatter = new OurFormatter();
144+
records.forEach(record -> System.out.print(formatter.format(record)));
145+
}
146+
}
147+
148+
private static class OurFormatter extends Formatter {
149+
150+
private final DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("HH:mm:ss.SSS");
151+
152+
@Override
153+
public String format(LogRecord record) {
154+
StringBuilder buffer = new StringBuilder();
155+
LocalDateTime dateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(record.getMillis()), ZoneId.systemDefault());
156+
buffer.append(dateFormat.format(dateTime));
157+
buffer.append(' ');
158+
buffer.append(record.getLevel());
159+
if (record.getSourceClassName() != null) {
160+
String[] parts = record.getSourceClassName().split("\\.");
161+
buffer.append(" [").append(parts[parts.length - 1]).append(".").append(record.getSourceMethodName()).append("]");
162+
}
163+
buffer.append(" - ");
164+
buffer.append(formatMessage(record)).append(System.getProperty("line.separator"));
165+
if (record.getThrown() != null) {
166+
final StringWriter trace = new StringWriter();
167+
record.getThrown().printStackTrace(new PrintWriter(trace));
168+
buffer.append(trace);
169+
}
170+
171+
return buffer.toString();
172+
}
173+
}
174+
}

java/client/test/org/openqa/selenium/testing/SeleniumTestRule.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ public SeleniumTestRule(Duration regularWait, Duration shortWait) {
3636
this.regularWait = Require.nonNull("Regular wait duration", regularWait);
3737
this.shortWait = Require.nonNull("Short wait duration", shortWait);
3838

39-
this.chain = RuleChain.outerRule(new TraceMethodNameRule())
39+
this.chain = RuleChain.outerRule(new CaptureLoggingRule())
40+
.around(new TraceMethodNameRule())
4041
.around(new ManageDriverRule())
4142
.around(new SwitchToTopRule())
4243
.around(new NotYetImplementedRule());

java/client/test/org/openqa/selenium/testing/drivers/WebDriverBuilder.java

-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ static void addShutdownAction(Runnable action) {
6363
new ImmutableMap.Builder<Browser, Function<Capabilities, Capabilities>>()
6464
.put(Browser.CHROME, original -> new ChromeOptions().merge(original))
6565
.put(Browser.FIREFOX, original -> new FirefoxOptions(original)
66-
.setLegacy(true)
6766
.setHeadless(Boolean.parseBoolean(System.getProperty("webdriver.firefox.headless", "false"))))
6867
.put(Browser.MARIONETTE, original -> new FirefoxOptions(original)
6968
.setHeadless(Boolean.parseBoolean(System.getProperty("webdriver.firefox.headless", "false")))

java/server/src/org/openqa/selenium/grid/log/TerseFormatter.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public class TerseFormatter extends Formatter {
5858
* allocations.
5959
*/
6060
private final StringBuilder buffer;
61-
private SimpleDateFormat timestampFormatter;
61+
private final SimpleDateFormat timestampFormatter;
6262

6363
public TerseFormatter() {
6464
buffer = new StringBuilder();

0 commit comments

Comments
 (0)