From c165afb4d5a0d90ac214307beb16fc10513c8995 Mon Sep 17 00:00:00 2001 From: Igor Motov Date: Thu, 30 Apr 2015 13:47:19 -0400 Subject: [PATCH] Logging: Add logging of slow cluster state tasks Closes #10874 --- .../service/InternalClusterService.java | 42 +++- .../ClusterDynamicSettingsModule.java | 2 + .../cluster/ClusterServiceTests.java | 216 +++++++++++++++++- .../elasticsearch/test/MockLogAppender.java | 139 +++++++++++ 4 files changed, 392 insertions(+), 7 deletions(-) create mode 100644 src/test/java/org/elasticsearch/test/MockLogAppender.java diff --git a/src/main/java/org/elasticsearch/cluster/service/InternalClusterService.java b/src/main/java/org/elasticsearch/cluster/service/InternalClusterService.java index b1823e5d74e..a5b7470bfa1 100644 --- a/src/main/java/org/elasticsearch/cluster/service/InternalClusterService.java +++ b/src/main/java/org/elasticsearch/cluster/service/InternalClusterService.java @@ -20,7 +20,6 @@ package org.elasticsearch.cluster.service; import com.google.common.collect.Iterables; -import org.elasticsearch.ElasticsearchException; import org.elasticsearch.Version; import org.elasticsearch.cluster.*; import org.elasticsearch.cluster.ClusterState.Builder; @@ -59,6 +58,9 @@ import static org.elasticsearch.common.util.concurrent.EsExecutors.daemonThreadF */ public class InternalClusterService extends AbstractLifecycleComponent implements ClusterService { + public static final String SETTING_CLUSTER_SERVICE_SLOW_TASK_LOGGING_THRESHOLD = "cluster.service.slow_task_logging_threshold"; + public static final String SETTING_CLUSTER_SERVICE_RECONNECT_INTERVAL = "cluster.service.reconnect_interval"; + public static final String UPDATE_THREAD_NAME = "clusterService#updateTask"; private final ThreadPool threadPool; @@ -74,6 +76,8 @@ public class InternalClusterService extends AbstractLifecycleComponent slowTaskLoggingThreshold.getMillis()) { + logger.warn("cluster state update task [{}] took {} above the warn threshold of {}", source, executionTime, slowTaskLoggingThreshold); + } + } + class NotifyTimeout implements Runnable { final TimeoutClusterStateListener listener; final TimeValue timeout; @@ -755,4 +776,13 @@ public class InternalClusterService extends AbstractLifecycleComponent expectations; + + public MockLogAppender() { + expectations = newArrayList(); + } + + public void addExpectation(LoggingExpectation expectation) { + expectations.add(expectation); + } + + @Override + protected void append(LoggingEvent loggingEvent) { + for (LoggingExpectation expectation : expectations) { + expectation.match(loggingEvent); + } + } + + @Override + public void close() { + + } + + @Override + public boolean requiresLayout() { + return false; + } + + public void assertAllExpectationsMatched() { + for (LoggingExpectation expectation : expectations) { + expectation.assertMatched(); + } + } + + public interface LoggingExpectation { + void match(LoggingEvent loggingEvent); + + void assertMatched(); + } + + public static abstract class AbstractEventExpectation implements LoggingExpectation { + protected final String name; + protected final String logger; + protected final Level level; + protected final String message; + protected boolean saw; + + public AbstractEventExpectation(String name, String logger, Level level, String message) { + this.name = name; + this.logger = getLoggerName(logger); + this.level = level; + this.message = message; + this.saw = false; + } + + @Override + public void match(LoggingEvent event) { + if (event.getLevel() == level && event.getLoggerName().equals(logger)) { + if (Regex.isSimpleMatchPattern(message)) { + if (Regex.simpleMatch(message, event.getMessage().toString())) { + saw = true; + } + } else { + if (event.getMessage().toString().contains(message)) { + saw = true; + } + } + } + } + } + + public static class UnseenEventExpectation extends AbstractEventExpectation { + + public UnseenEventExpectation(String name, String logger, Level level, String message) { + super(name, logger, level, message); + } + + @Override + public void assertMatched() { + assertThat(name, saw, equalTo(false)); + } + } + + public static class SeenEventExpectation extends AbstractEventExpectation { + + public SeenEventExpectation(String name, String logger, Level level, String message) { + super(name, logger, level, message); + } + + @Override + public void assertMatched() { + assertThat(name, saw, equalTo(true)); + } + } + + private static String getLoggerName(String name) { + if (name.startsWith("org.elasticsearch.")) { + name = name.substring("org.elasticsearch.".length()); + } + return COMMON_PREFIX + name; + } +}