Skip to content

Commit 47ab2bd

Browse files
committed
Improve how log is tailed in testclusters on failure (#40600)
* Improoce how log is tailed in testclusters on failure - only print last few lines - print all errors and warnings - compact repeating errors and warnings
1 parent eace735 commit 47ab2bd

File tree

3 files changed

+83
-12
lines changed

3 files changed

+83
-12
lines changed

buildSrc/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchNode.java

Lines changed: 76 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@
4646
import java.io.File;
4747
import java.io.IOException;
4848
import java.io.InputStream;
49+
import java.io.LineNumberReader;
50+
4951
import java.io.UncheckedIOException;
5052
import java.net.URI;
5153
import java.nio.charset.StandardCharsets;
@@ -61,6 +63,7 @@
6163
import java.util.HashMap;
6264
import java.util.HashSet;
6365
import java.util.LinkedHashMap;
66+
import java.util.LinkedList;
6467
import java.util.List;
6568
import java.util.Map;
6669
import java.util.Objects;
@@ -82,13 +85,22 @@ public class ElasticsearchNode implements TestClusterConfiguration {
8285
private static final Logger LOGGER = Logging.getLogger(ElasticsearchNode.class);
8386
private static final int ES_DESTROY_TIMEOUT = 20;
8487
private static final TimeUnit ES_DESTROY_TIMEOUT_UNIT = TimeUnit.SECONDS;
88+
8589
private static final int NODE_UP_TIMEOUT = 2;
8690
private static final TimeUnit NODE_UP_TIMEOUT_UNIT = TimeUnit.MINUTES;
8791
private static final int ADDITIONAL_CONFIG_TIMEOUT = 15;
8892
private static final TimeUnit ADDITIONAL_CONFIG_TIMEOUT_UNIT = TimeUnit.SECONDS;
8993
private static final List<String> OVERRIDABLE_SETTINGS = Arrays.asList(
9094
"path.repo",
9195
"discovery.seed_providers"
96+
97+
);
98+
99+
private static final int TAIL_LOG_MESSAGES_COUNT = 40;
100+
private static final List<String> MESSAGES_WE_DONT_CARE_ABOUT = Arrays.asList(
101+
"Option UseConcMarkSweepGC was deprecated",
102+
"is a pre-release version of Elasticsearch",
103+
"max virtual memory areas vm.max_map_count"
92104
);
93105

94106
private final String path;
@@ -693,14 +705,73 @@ private void logProcessInfo(String prefix, ProcessHandle.Info info) {
693705
}
694706

695707
private void logFileContents(String description, Path from) {
696-
LOGGER.error("{} `{}`", description, this);
697-
try (Stream<String> lines = Files.lines(from, StandardCharsets.UTF_8)) {
698-
lines
699-
.map(line -> " " + line)
700-
.forEach(LOGGER::error);
708+
final Map<String, Integer> errorsAndWarnings = new LinkedHashMap<>();
709+
LinkedList<String> ring = new LinkedList<>();
710+
try (LineNumberReader reader = new LineNumberReader(Files.newBufferedReader(from))) {
711+
for (String line = reader.readLine(); line != null ; line = reader.readLine()) {
712+
final String lineToAdd;
713+
if (ring.isEmpty()) {
714+
lineToAdd = line;
715+
} else {
716+
if (line.startsWith("[")) {
717+
lineToAdd = line;
718+
// check to see if the previous message (possibly combined from multiple lines) was an error or
719+
// warning as we want to show all of them
720+
String previousMessage = normalizeLogLine(ring.getLast());
721+
if (MESSAGES_WE_DONT_CARE_ABOUT.stream().noneMatch(previousMessage::contains) &&
722+
(previousMessage.contains("ERROR") || previousMessage.contains("WARN"))) {
723+
errorsAndWarnings.put(
724+
previousMessage,
725+
errorsAndWarnings.getOrDefault(previousMessage, 0) + 1
726+
);
727+
}
728+
} else {
729+
// We combine multi line log messages to make sure we never break exceptions apart
730+
lineToAdd = ring.removeLast() + "\n" + line;
731+
}
732+
}
733+
ring.add(lineToAdd);
734+
if (ring.size() >= TAIL_LOG_MESSAGES_COUNT) {
735+
ring.removeFirst();
736+
}
737+
}
701738
} catch (IOException e) {
702739
throw new UncheckedIOException("Failed to tail log " + this, e);
703740
}
741+
742+
if (errorsAndWarnings.isEmpty() == false || ring.isEmpty() == false) {
743+
LOGGER.error("\n=== {} `{}` ===", description, this);
744+
}
745+
if (errorsAndWarnings.isEmpty() == false) {
746+
LOGGER.lifecycle("\n» ↓ errors and warnings from " + from + " ↓");
747+
errorsAndWarnings.forEach((message, count) -> {
748+
LOGGER.lifecycle("» " + message.replace("\n", "\n» "));
749+
if (count > 1) {
750+
LOGGER.lifecycle("» ↑ repeated " + count + " times ↑");
751+
}
752+
});
753+
}
754+
755+
ring.removeIf(line -> MESSAGES_WE_DONT_CARE_ABOUT.stream().anyMatch(line::contains));
756+
757+
if (ring.isEmpty() == false) {
758+
LOGGER.lifecycle("» ↓ last " + TAIL_LOG_MESSAGES_COUNT + " non error or warning messages from " + from + " ↓");
759+
ring.forEach(message -> {
760+
if (errorsAndWarnings.containsKey(normalizeLogLine(message)) == false) {
761+
LOGGER.lifecycle("» " + message.replace("\n", "\n» "));
762+
}
763+
});
764+
}
765+
}
766+
767+
private String normalizeLogLine(String line) {
768+
if (line.contains("ERROR")) {
769+
return line.substring(line.indexOf("ERROR"));
770+
}
771+
if (line.contains("WARN")) {
772+
return line.substring(line.indexOf("WARN"));
773+
}
774+
return line;
704775
}
705776

706777
private void waitForProcessToExit(ProcessHandle processHandle) {

buildSrc/src/test/java/org/elasticsearch/gradle/testclusters/TestClustersPluginIT.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,9 @@ public void testUseClusterByTwo() {
6868
public void testUseClusterByUpToDateTask() {
6969
// Run it once, ignoring the result and again to make sure it's considered up to date.
7070
// Gradle randomly considers tasks without inputs and outputs as as up-to-date or success on the first run
71-
getTestClustersRunner(":upToDate1", ":upToDate2").build();
72-
BuildResult result = getTestClustersRunner(":upToDate1", ":upToDate2").build();
73-
assertTaskUpToDate(result, ":upToDate1", ":upToDate2");
71+
getTestClustersRunner(":upToDate1").build();
72+
BuildResult result = getTestClustersRunner(":upToDate1").build();
73+
assertTaskUpToDate(result, ":upToDate1");
7474
assertNotStarted(result);
7575
}
7676

buildSrc/src/testKit/testclusters/build.gradle

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,10 @@ task printLog {
105105

106106
task upToDate1 {
107107
useCluster testClusters.myTestCluster
108-
}
109-
110-
task upToDate2 {
111-
useCluster testClusters.myTestCluster
108+
outputs.upToDateWhen { true }
109+
doLast {
110+
println "Some task action"
111+
}
112112
}
113113

114114
task skipped1 {

0 commit comments

Comments
 (0)