Merge branch 'stable-2.14' into stable-2.15
* stable-2.14:
Introduce the changes query healthcheck
Config: allow per-check timeout configuration
Send metrics when running healthcheck
Fix ListProjects constructor in IT
Change-Id: I4e83111b5c1981cfd3da82ad1bf67d693d3b5eaf
diff --git a/README.md b/README.md
index edb538d..fe38bc8 100644
--- a/README.md
+++ b/README.md
@@ -39,7 +39,7 @@
- elapsed: elapsed time in millis to perform the check
- reviewdb: check that Gerrit can connect and query ReviewDb
- projectslist: check that Gerrit can list projects
-- auth: check that Gerrit can authenticate users
+- jgit: check that Gerrit can access repositories
Each check returns a JSON payload with the following information:
@@ -72,7 +72,7 @@
"elapsed": 100,
"result": "passed"
},
- "auth": {
+ "jgit": {
"ts": 139402910202,
"elapsed": 80,
"result": "passed"
@@ -101,7 +101,7 @@
"elapsed": 100,
"result": "timeout"
},
- "auth": {
+ "jgit": {
"ts": 139402910202,
"elapsed": 80,
"result": "passed"
@@ -109,3 +109,12 @@
}
```
+## Metrics
+
+As for all other endpoints in Gerrit, some metrics are automatically emitted when the `/config/server/healthcheck~status`
+endpoint is hit (thanks to the [Dropwizard](https://metrics.dropwizard.io/3.1.0/manual/core/) library).
+
+Some additional metrics are also produced to give extra insights on their result about results and latency of healthcheck
+sub component, such as jgit, reviewdb, etc.
+
+More information can be found in the [config.md](resources/Documentation/config.md) file.
\ No newline at end of file
diff --git a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckConfig.java b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckConfig.java
new file mode 100644
index 0000000..6c93e91
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckConfig.java
@@ -0,0 +1,75 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.googlesource.gerrit.plugins.healthcheck;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Strings;
+import com.google.gerrit.extensions.annotations.PluginName;
+import com.google.gerrit.server.config.PluginConfigFactory;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import java.util.concurrent.TimeUnit;
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.lib.Config;
+
+@Singleton
+public class HealthCheckConfig {
+ public static final String HEALTHCHECK = "healthcheck";
+ public static final HealthCheckConfig DEFAULT_CONFIG = new HealthCheckConfig(null);
+ private static final long HEALTHCHECK_TIMEOUT_DEFAULT = 500L;
+ private static final String QUERY_DEFAULT = "status:open";
+ private static final int LIMIT_DEFAULT = 10;
+
+ private final Config config;
+
+ @Inject
+ public HealthCheckConfig(PluginConfigFactory configFactory, @PluginName String pluginName) {
+ config = configFactory.getGlobalPluginConfig(pluginName);
+ }
+
+ @VisibleForTesting
+ public HealthCheckConfig(String configText) {
+ config = new Config();
+ if (!Strings.isNullOrEmpty(configText)) {
+ try {
+ config.fromText(configText);
+ } catch (ConfigInvalidException e) {
+ throw new IllegalArgumentException("Invalid configuration " + configText, e);
+ }
+ }
+ }
+
+ public long getTimeout() {
+ return getTimeout(null);
+ }
+
+ public long getTimeout(String healthCheckName) {
+ long defaultTimeout = healthCheckName == null ? HEALTHCHECK_TIMEOUT_DEFAULT : getTimeout(null);
+ return config.getTimeUnit(
+ HEALTHCHECK, healthCheckName, "timeout", defaultTimeout, TimeUnit.MILLISECONDS);
+ }
+
+ public String getQuery(String healthCheckName) {
+ String defaultQuery = healthCheckName == null ? QUERY_DEFAULT : getQuery(null);
+ return MoreObjects.firstNonNull(
+ config.getString(HEALTHCHECK, healthCheckName, "query"), defaultQuery);
+ }
+
+ public int getLimit(String healthCheckName) {
+ int defaultLimit = healthCheckName == null ? LIMIT_DEFAULT : getLimit(null);
+ return config.getInt(HEALTHCHECK, healthCheckName, "limit", defaultLimit);
+ }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckSubsystemsModule.java b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckSubsystemsModule.java
index 5857bc4..9c6b17d 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckSubsystemsModule.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckSubsystemsModule.java
@@ -16,18 +16,27 @@
import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.inject.AbstractModule;
+import com.google.inject.assistedinject.FactoryModuleBuilder;
import com.googlesource.gerrit.plugins.healthcheck.check.HealthCheck;
import com.googlesource.gerrit.plugins.healthcheck.check.JGitHealthCheck;
+import com.googlesource.gerrit.plugins.healthcheck.check.MetricsHandler;
import com.googlesource.gerrit.plugins.healthcheck.check.ProjectsListHealthCheck;
+import com.googlesource.gerrit.plugins.healthcheck.check.QueryChangesHealthCheck;
import com.googlesource.gerrit.plugins.healthcheck.check.ReviewDbHealthCheck;
public class HealthCheckSubsystemsModule extends AbstractModule {
@Override
protected void configure() {
+ install(
+ new FactoryModuleBuilder()
+ .implement(MetricsHandler.class, MetricsHandler.class)
+ .build(MetricsHandler.Factory.class));
+
bindChecker(ReviewDbHealthCheck.class);
bindChecker(JGitHealthCheck.class);
bindChecker(ProjectsListHealthCheck.class);
+ bindChecker(QueryChangesHealthCheck.class);
}
private void bindChecker(Class<? extends HealthCheck> healthCheckClass) {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/AbstractHealthCheck.java b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/AbstractHealthCheck.java
index 5c8d410..8aa6432 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/AbstractHealthCheck.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/AbstractHealthCheck.java
@@ -16,6 +16,7 @@
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
+import com.googlesource.gerrit.plugins.healthcheck.HealthCheckConfig;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@@ -24,13 +25,20 @@
public abstract class AbstractHealthCheck implements HealthCheck {
private static final Logger log = LoggerFactory.getLogger(AbstractHealthCheck.class);
- public static final long CHECK_TIMEOUT = 500L;
+ private final long timeout;
private final String name;
private final ListeningExecutorService executor;
+ private final MetricsHandler metricsHandler;
- protected AbstractHealthCheck(ListeningExecutorService executor, String name) {
+ protected AbstractHealthCheck(
+ ListeningExecutorService executor,
+ HealthCheckConfig config,
+ String name,
+ MetricsHandler.Factory metricsHandler) {
this.executor = executor;
this.name = name;
+ this.metricsHandler = metricsHandler.create(name);
+ this.timeout = config.getTimeout(name);
}
@Override
@@ -41,6 +49,7 @@
@Override
public Status run() {
final long ts = System.currentTimeMillis();
+ Status status = null;
ListenableFuture<Status> resultFuture =
executor.submit(
() -> {
@@ -53,16 +62,18 @@
}
return new Status(healthy, ts, System.currentTimeMillis() - ts);
});
-
try {
- return resultFuture.get(CHECK_TIMEOUT, TimeUnit.MILLISECONDS);
+ status = resultFuture.get(timeout, TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
log.warn("Check {} timed out", name, e);
- return new Status(Result.TIMEOUT, ts, System.currentTimeMillis() - ts);
+ status = new Status(Result.TIMEOUT, ts, System.currentTimeMillis() - ts);
} catch (InterruptedException | ExecutionException e) {
log.warn("Check {} failed while waiting for its future result", name, e);
- return new Status(Result.FAILED, ts, System.currentTimeMillis() - ts);
+ status = new Status(Result.FAILED, ts, System.currentTimeMillis() - ts);
+ } finally {
+ metricsHandler.sendMetrics(status);
}
+ return status;
}
protected abstract Result doCheck() throws Exception;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/HealthCheck.java b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/HealthCheck.java
index 355b0cf..6f44ca4 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/HealthCheck.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/HealthCheck.java
@@ -37,6 +37,10 @@
this.ts = ts;
this.elapsed = elapsed;
}
+
+ protected Boolean isFailure() {
+ return this.result != Result.PASSED;
+ }
}
Status run();
diff --git a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/HealthCheckNames.java b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/HealthCheckNames.java
index 2eb896e..402fa35 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/HealthCheckNames.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/HealthCheckNames.java
@@ -18,4 +18,5 @@
String REVIEWDB = "reviewdb";
String JGIT = "jgit";
String PROJECTSLIST = "projectslist";
+ String QUERYCHANGES = "querychanges";
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/JGitHealthCheck.java b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/JGitHealthCheck.java
index a23e0d1..90c9fd9 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/JGitHealthCheck.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/JGitHealthCheck.java
@@ -20,6 +20,7 @@
import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.inject.Inject;
+import com.googlesource.gerrit.plugins.healthcheck.HealthCheckConfig;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
@@ -30,9 +31,11 @@
@Inject
public JGitHealthCheck(
ListeningExecutorService executor,
+ HealthCheckConfig config,
GitRepositoryManager repositoryManager,
- AllProjectsName allProjectsName) {
- super(executor, JGIT);
+ AllProjectsName allProjectsName,
+ MetricsHandler.Factory metricsHandlerFactory) {
+ super(executor, config, JGIT, metricsHandlerFactory);
this.repositoryManager = repositoryManager;
this.allProjectsName = allProjectsName;
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/MetricsHandler.java b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/MetricsHandler.java
new file mode 100644
index 0000000..c28f52a
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/MetricsHandler.java
@@ -0,0 +1,43 @@
+package com.googlesource.gerrit.plugins.healthcheck.check;
+
+import com.google.gerrit.metrics.Counter0;
+import com.google.gerrit.metrics.Description;
+import com.google.gerrit.metrics.MetricMaker;
+import com.google.gerrit.metrics.Timer0;
+import com.google.inject.Inject;
+import com.google.inject.assistedinject.Assisted;
+import java.util.concurrent.TimeUnit;
+
+public class MetricsHandler {
+ private final Timer0 latencyMetric;
+ private final Counter0 failureMetric;
+
+ public interface Factory {
+ public MetricsHandler create(String name);
+ }
+
+ @Inject
+ public MetricsHandler(@Assisted String name, MetricMaker metricMaker) {
+ this.latencyMetric =
+ metricMaker.newTimer(
+ name + "/latency",
+ new Description(String.format("%s health check latency execution (ms)", name))
+ .setCumulative()
+ .setUnit(Description.Units.MILLISECONDS));
+
+ this.failureMetric =
+ metricMaker.newCounter(
+ name + "/failure",
+ new Description(String.format("%s healthcheck failures count", name))
+ .setCumulative()
+ .setRate()
+ .setUnit("failures"));
+ }
+
+ public void sendMetrics(HealthCheck.Status status) {
+ latencyMetric.record(status.elapsed, TimeUnit.MILLISECONDS);
+ if (status.isFailure()) {
+ failureMetric.increment();
+ }
+ }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/ProjectsListHealthCheck.java b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/ProjectsListHealthCheck.java
index 580f3a0..0c9a120 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/ProjectsListHealthCheck.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/ProjectsListHealthCheck.java
@@ -20,6 +20,7 @@
import com.google.gerrit.extensions.common.ProjectInfo;
import com.google.gerrit.server.project.ListProjects;
import com.google.inject.Inject;
+import com.googlesource.gerrit.plugins.healthcheck.HealthCheckConfig;
import java.util.SortedMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -30,8 +31,12 @@
private final ListProjects listProjects;
@Inject
- public ProjectsListHealthCheck(ListeningExecutorService executor, ListProjects listProjects) {
- super(executor, PROJECTSLIST);
+ public ProjectsListHealthCheck(
+ ListeningExecutorService executor,
+ HealthCheckConfig config,
+ ListProjects listProjects,
+ MetricsHandler.Factory metricHandlerFactory) {
+ super(executor, config, PROJECTSLIST, metricHandlerFactory);
this.listProjects = listProjects;
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/QueryChangesHealthCheck.java b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/QueryChangesHealthCheck.java
new file mode 100644
index 0000000..67bb733
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/QueryChangesHealthCheck.java
@@ -0,0 +1,71 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.googlesource.gerrit.plugins.healthcheck.check;
+
+import static com.googlesource.gerrit.plugins.healthcheck.check.HealthCheckNames.QUERYCHANGES;
+
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.gerrit.server.query.change.QueryChanges;
+import com.google.gerrit.server.util.ManualRequestContext;
+import com.google.gerrit.server.util.OneOffRequestContext;
+import com.google.inject.Inject;
+import com.googlesource.gerrit.plugins.healthcheck.HealthCheckConfig;
+import java.util.List;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class QueryChangesHealthCheck extends AbstractHealthCheck {
+ private static final Logger log = LoggerFactory.getLogger(QueryChangesHealthCheck.class);
+ private final QueryChanges queryChanges;
+ private final int limit;
+ private final OneOffRequestContext oneOffCtx;
+
+ @Inject
+ public QueryChangesHealthCheck(
+ ListeningExecutorService executor,
+ HealthCheckConfig config,
+ QueryChanges queryChanges,
+ OneOffRequestContext oneOffCtx,
+ MetricsHandler.Factory metricsHandlerFactory) {
+ super(executor, config, QUERYCHANGES, metricsHandlerFactory);
+ this.queryChanges = queryChanges;
+ this.limit = config.getLimit(QUERYCHANGES);
+ queryChanges.setLimit(limit);
+ queryChanges.addQuery(config.getQuery(QUERYCHANGES));
+ queryChanges.setStart(0);
+ this.oneOffCtx = oneOffCtx;
+ }
+
+ @Override
+ protected Result doCheck() throws Exception {
+ try (ManualRequestContext ctx = oneOffCtx.open()) {
+ List<?> changes = queryChanges.apply(null);
+ if (changes == null) {
+ log.warn("Cannot query changes: received a null list of results");
+ return Result.FAILED;
+ }
+
+ if (changes.size() < limit) {
+ log.warn(
+ "Query changes did not return enough items: expected {} items but got only {}",
+ limit,
+ changes.size());
+ return Result.FAILED;
+ }
+
+ return Result.PASSED;
+ }
+ }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/ReviewDbHealthCheck.java b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/ReviewDbHealthCheck.java
index 138997b..805eaa1 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/ReviewDbHealthCheck.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/ReviewDbHealthCheck.java
@@ -21,13 +21,18 @@
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gwtorm.server.SchemaFactory;
import com.google.inject.Inject;
+import com.googlesource.gerrit.plugins.healthcheck.HealthCheckConfig;
public class ReviewDbHealthCheck extends AbstractHealthCheck {
private final SchemaFactory<ReviewDb> reviewDb;
@Inject
- public ReviewDbHealthCheck(ListeningExecutorService executor, SchemaFactory<ReviewDb> reviewDb) {
- super(executor, REVIEWDB);
+ public ReviewDbHealthCheck(
+ ListeningExecutorService executor,
+ HealthCheckConfig config,
+ SchemaFactory<ReviewDb> reviewDb,
+ MetricsHandler.Factory metricHandlerFactory) {
+ super(executor, config, REVIEWDB, metricHandlerFactory);
this.reviewDb = reviewDb;
}
diff --git a/src/main/resources/Documentation/about.md b/src/main/resources/Documentation/about.md
new file mode 100644
index 0000000..b2f798d
--- /dev/null
+++ b/src/main/resources/Documentation/about.md
@@ -0,0 +1,3 @@
+This plugin provides support for monitoring and alerting purposes.
+A common use-case is the automatic detection and recovery of issues
+for Gerrit Servers that need to be available on a 24x7 basis.
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md
new file mode 100644
index 0000000..74ad62c
--- /dev/null
+++ b/src/main/resources/Documentation/config.md
@@ -0,0 +1,66 @@
+@PLUGIN@ configuration
+======================
+
+The @PLUGIN@
+------------
+
+The plugin does not require any configuration at all and exposes an HTTP
+endpoint for querying the service status.
+
+```
+GET /config/server/healthcheck~status
+
+)]}'
+{
+ "ts": 139402910202,
+ "elapsed": 100,
+ "reviewdb": {
+ "ts": 139402910202,
+ "elapsed": 50,
+ "result": "passed"
+ },
+ "projectslist": {
+ "ts": 139402910202,
+ "elapsed": 100,
+ "result": "passed"
+ },
+ "auth": {
+ "ts": 139402910202,
+ "elapsed": 80,
+ "result": "passed"
+ }
+}
+```
+
+Settings
+--------
+
+The plugin allows to customize its behaviour through a specific
+`healthcheck.config` file in the `$GERRIT_SITE/etc` directory.
+
+Each section of the form `[healthcheck "<checkName>"]` can tailor the
+behaviour of an individual `<checkName>`. The section `[healthcheck]`
+defines the global defaults valid for all checks.
+
+The following check names are available:
+
+- `reviewdb` : check connectivity and ability to query ReviewDb
+- `jgit` : check connectivity to the filesystem and ability to open a JGit ref and object
+- `projectslist` : check the ability to list projects with their descriptions
+
+The follwing parameters are available:
+
+- `healthcheck.<checkName>.timeout` : Specific timeout (msec) for the
+ healthcheck to complete. Zero means that there is no timeout.
+
+ Default: 500
+
+- `healthcheck.<checkName>.query` : Query to be executed for extracting
+ elements from the check.
+
+ Default: status:open
+
+- `healthcheck.<checkName>.limit` : Maximum number of elements to retrieve from
+ the the check results.
+
+ Default: 10
\ No newline at end of file
diff --git a/src/resources/Documentation/config.md b/src/resources/Documentation/config.md
new file mode 100644
index 0000000..72a3ad5
--- /dev/null
+++ b/src/resources/Documentation/config.md
@@ -0,0 +1,86 @@
+## Metrics
+
+As for all other endpoints in Gerrit, some metrics are automatically emitted when the `/config/server/healthcheck~status`
+endpoint is hit (thanks to the [Dropwizard](https://metrics.dropwizard.io/3.1.0/manual/core/) library).
+For example, some of the metrics exposed will be:
+
+```
+# HELP http_server_rest_api_response_bytes_healthcheck_com_googlesource_gerrit_plugins_healthcheck_api_HealthCheckStatusEndpoint Generated from Dropwizard metric import (metric=http/server/rest_api/response_bytes/healthcheck-com.googlesource.gerrit.plugins.healthcheck.api.HealthCheckStatusEndpoint, type=com.codahale.metrics.Histogram)
+# TYPE http_server_rest_api_response_bytes_healthcheck_com_googlesource_gerrit_plugins_healthcheck_api_HealthCheckStatusEndpoint summary
+http_server_rest_api_response_bytes_healthcheck_com_googlesource_gerrit_plugins_healthcheck_api_HealthCheckStatusEndpoint{quantile="0.5",} 308.0
+http_server_rest_api_response_bytes_healthcheck_com_googlesource_gerrit_plugins_healthcheck_api_HealthCheckStatusEndpoint{quantile="0.75",} 308.0
+http_server_rest_api_response_bytes_healthcheck_com_googlesource_gerrit_plugins_healthcheck_api_HealthCheckStatusEndpoint{quantile="0.95",} 308.0
+http_server_rest_api_response_bytes_healthcheck_com_googlesource_gerrit_plugins_healthcheck_api_HealthCheckStatusEndpoint{quantile="0.98",} 310.0
+http_server_rest_api_response_bytes_healthcheck_com_googlesource_gerrit_plugins_healthcheck_api_HealthCheckStatusEndpoint{quantile="0.99",} 310.0
+http_server_rest_api_response_bytes_healthcheck_com_googlesource_gerrit_plugins_healthcheck_api_HealthCheckStatusEndpoint{quantile="0.999",} 310.0
+http_server_rest_api_response_bytes_healthcheck_com_googlesource_gerrit_plugins_healthcheck_api_HealthCheckStatusEndpoint_count 4.0
+
+# HELP http_server_rest_api_server_latency_healthcheck_com_googlesource_gerrit_plugins_healthcheck_api_HealthCheckStatusEndpoint Generated from Dropwizard metric import (metric=http/server/rest_api/server_latency/healthcheck-com.googlesource.gerrit.plugins.healthcheck.api.HealthCheckStatusEndpoint, type=com.codahale.metrics.Timer)
+# TYPE http_server_rest_api_server_latency_healthcheck_com_googlesource_gerrit_plugins_healthcheck_api_HealthCheckStatusEndpoint summary
+http_server_rest_api_server_latency_healthcheck_com_googlesource_gerrit_plugins_healthcheck_api_HealthCheckStatusEndpoint{quantile="0.5",} 0.008638662
+http_server_rest_api_server_latency_healthcheck_com_googlesource_gerrit_plugins_healthcheck_api_HealthCheckStatusEndpoint{quantile="0.75",} 0.008638662
+http_server_rest_api_server_latency_healthcheck_com_googlesource_gerrit_plugins_healthcheck_api_HealthCheckStatusEndpoint{quantile="0.95",} 0.010553707
+http_server_rest_api_server_latency_healthcheck_com_googlesource_gerrit_plugins_healthcheck_api_HealthCheckStatusEndpoint{quantile="0.98",} 0.147902061
+http_server_rest_api_server_latency_healthcheck_com_googlesource_gerrit_plugins_healthcheck_api_HealthCheckStatusEndpoint{quantile="0.99",} 0.147902061
+http_server_rest_api_server_latency_healthcheck_com_googlesource_gerrit_plugins_healthcheck_api_HealthCheckStatusEndpoint{quantile="0.999",} 0.147902061
+http_server_rest_api_server_latency_healthcheck_com_googlesource_gerrit_plugins_healthcheck_api_HealthCheckStatusEndpoint_count 4.0
+
+# HELP http_server_rest_api_count_healthcheck_com_googlesource_gerrit_plugins_healthcheck_api_HealthCheckStatusEndpoint_total Generated from Dropwizard metric import (metric=http/server/rest_api/count/healthcheck-com.googlesource.gerrit.plugins.healthcheck.api.HealthCheckStatusEndpoint, type=com.codahale.metrics.Meter)
+# TYPE http_server_rest_api_count_healthcheck_com_googlesource_gerrit_plugins_healthcheck_api_HealthCheckStatusEndpoint_total counter
+http_server_rest_api_count_healthcheck_com_googlesource_gerrit_plugins_healthcheck_api_HealthCheckStatusEndpoint_total 4.0
+
+# HELP http_server_rest_api_error_count_healthcheck_com_googlesource_gerrit_plugins_healthcheck_api_HealthCheckStatusEndpoint_500_total Generated from Dropwizard metric import (metric=http/server/rest_api/error_count/healthcheck-com.googlesource.gerrit.plugins.healthcheck.api.HealthCheckStatusEndpoint/500, type=com.codahale.metrics.Meter)
+# TYPE http_server_rest_api_error_count_healthcheck_com_googlesource_gerrit_plugins_healthcheck_api_HealthCheckStatusEndpoint_500_total counter
+http_server_rest_api_error_count_healthcheck_com_googlesource_gerrit_plugins_healthcheck_api_HealthCheckStatusEndpoint_500_total 2.0
+```
+
+However some extra metrics are also emitted to expose more details about the healthcheck result.
+Specifically two metrics are emitted for each component contributing to the overall healthcheck result (JGIT, PROJECTLIST, REVIEWDB).
+* plugins_healthcheck_<healthcheck_component>_latency: the cumulative latency (in ms) of performing the healthcheck for this specific component
+* plugins_healthcheck_jgit_failure_total: the cumulative number of failures for this specific component
+
+```
+# HELP plugins_healthcheck_jgit_latency Generated from Dropwizard metric import (metric=plugins/healthcheck/jgit/latency, type=com.codahale.metrics.Timer)
+# TYPE plugins_healthcheck_jgit_latency summary
+plugins_healthcheck_jgit_latency{quantile="0.5",} 0.002
+plugins_healthcheck_jgit_latency{quantile="0.75",} 0.002
+plugins_healthcheck_jgit_latency{quantile="0.95",} 0.002
+plugins_healthcheck_jgit_latency{quantile="0.98",} 0.002
+plugins_healthcheck_jgit_latency{quantile="0.99",} 0.002
+plugins_healthcheck_jgit_latency{quantile="0.999",} 0.002
+plugins_healthcheck_jgit_latency_count 1.0
+
+# HELP plugins_healthcheck_projectslist_latency Generated from Dropwizard metric import (metric=plugins/healthcheck/projectslist/latency, type=com.codahale.metrics.Timer)
+# TYPE plugins_healthcheck_projectslist_latency summary
+plugins_healthcheck_projectslist_latency{quantile="0.5",} 0.001
+plugins_healthcheck_projectslist_latency{quantile="0.75",} 0.001
+plugins_healthcheck_projectslist_latency{quantile="0.95",} 0.001
+plugins_healthcheck_projectslist_latency{quantile="0.98",} 0.001
+plugins_healthcheck_projectslist_latency{quantile="0.99",} 0.001
+plugins_healthcheck_projectslist_latency{quantile="0.999",} 0.001
+plugins_healthcheck_projectslist_latency_count 1.0
+
+# HELP plugins_healthcheck_reviewdb_latency Generated from Dropwizard metric import (metric=plugins/healthcheck/reviewdb/latency, type=com.codahale.metrics.Timer)
+# TYPE plugins_healthcheck_reviewdb_latency summary
+plugins_healthcheck_reviewdb_latency{quantile="0.5",} 0.001
+plugins_healthcheck_reviewdb_latency{quantile="0.75",} 0.001
+plugins_healthcheck_reviewdb_latency{quantile="0.95",} 0.001
+plugins_healthcheck_reviewdb_latency{quantile="0.98",} 0.001
+plugins_healthcheck_reviewdb_latency{quantile="0.99",} 0.001
+plugins_healthcheck_reviewdb_latency{quantile="0.999",} 0.001
+plugins_healthcheck_reviewdb_latency_count 1.0
+
+# HELP plugins_healthcheck_jgit_failure_total Generated from Dropwizard metric import (metric=plugins/healthcheck/jgit/failure, type=com.codahale.metrics.Meter)
+# TYPE plugins_healthcheck_jgit_failure_total counter
+plugins_healthcheck_jgit_failure_total 0.0
+
+# HELP plugins_healthcheck_projectslist_failure_total Generated from Dropwizard metric import (metric=plugins/healthcheck/projectslist/failure, type=com.codahale.metrics.Meter)
+# TYPE plugins_healthcheck_projectslist_failure_total counter
+plugins_healthcheck_projectslist_failure_total 0.0
+
+# HELP plugins_healthcheck_reviewdb_failure_total Generated from Dropwizard metric import (metric=plugins/healthcheck/reviewdb/failure, type=com.codahale.metrics.Meter)
+# TYPE plugins_healthcheck_reviewdb_failure_total counter
+plugins_healthcheck_reviewdb_failure_total 0.0
+```
+
+Metrics will be exposed to prometheus by the [metrics-reporter-prometheus](https://gerrit.googlesource.com/plugins/metrics-reporter-prometheus/) plugin.
diff --git a/src/test/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckConfigTest.java b/src/test/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckConfigTest.java
new file mode 100644
index 0000000..fc215ff
--- /dev/null
+++ b/src/test/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckConfigTest.java
@@ -0,0 +1,48 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.googlesource.gerrit.plugins.healthcheck;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.googlesource.gerrit.plugins.healthcheck.HealthCheckConfig.DEFAULT_CONFIG;
+
+import org.junit.Test;
+
+public class HealthCheckConfigTest {
+
+ @Test
+ public void shouldHaveDefaultTimeout() {
+ long defaultTimeout = DEFAULT_CONFIG.getTimeout(null);
+ assertThat(defaultTimeout).isGreaterThan(0L);
+ assertThat(DEFAULT_CONFIG.getTimeout("fooCheck")).isEqualTo(defaultTimeout);
+ }
+
+ @Test
+ public void shouldHaveGlobalTimeout() {
+ HealthCheckConfig config = new HealthCheckConfig("[healthcheck]\n" + "timeout=1000");
+
+ assertThat(config.getTimeout(null)).isEqualTo(1000);
+ assertThat(config.getTimeout("barCheck")).isEqualTo(1000);
+ }
+
+ @Test
+ public void shouldHaveCheckOverriddenTimeout() {
+ HealthCheckConfig config =
+ new HealthCheckConfig(
+ "[healthcheck]\n" + "timeout=2000\n" + "[healthcheck \"fooCheck\"]\n" + "timeout=1000");
+
+ assertThat(config.getTimeout("fooCheck")).isEqualTo(1000);
+ assertThat(config.getTimeout("barCheck")).isEqualTo(2000);
+ }
+}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckIT.java b/src/test/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckIT.java
index 86a0965..38f807e 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckIT.java
@@ -17,21 +17,49 @@
import static com.google.common.net.HttpHeaders.CONTENT_TYPE;
import static com.google.common.truth.Truth.assertThat;
import static com.googlesource.gerrit.plugins.healthcheck.check.HealthCheckNames.JGIT;
+import static com.googlesource.gerrit.plugins.healthcheck.check.HealthCheckNames.QUERYCHANGES;
import static com.googlesource.gerrit.plugins.healthcheck.check.HealthCheckNames.REVIEWDB;
import com.google.gerrit.acceptance.LightweightPluginDaemonTest;
import com.google.gerrit.acceptance.RestResponse;
import com.google.gerrit.acceptance.Sandboxed;
import com.google.gerrit.acceptance.TestPlugin;
+import com.google.gerrit.extensions.annotations.PluginName;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
+import com.google.inject.AbstractModule;
+import com.googlesource.gerrit.plugins.healthcheck.check.HealthCheckNames;
import java.io.IOException;
+import org.junit.Before;
import org.junit.Test;
@TestPlugin(name = "healthcheck", sysModule = "com.googlesource.gerrit.plugins.healthcheck.Module")
@Sandboxed
public class HealthCheckIT extends LightweightPluginDaemonTest {
Gson gson = new Gson();
+ HealthCheckConfig config;
+
+ @Override
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+
+ config =
+ server
+ .getTestInjector()
+ .createChildInjector(
+ new AbstractModule() {
+ @Override
+ protected void configure() {
+ bind(String.class).annotatedWith(PluginName.class).toInstance("healthcheck");
+ }
+ })
+ .getInstance(HealthCheckConfig.class);
+ int numChanges = config.getLimit(HealthCheckNames.QUERYCHANGES);
+ for (int i = 0; i < numChanges; i++) {
+ createChange("refs/for/master");
+ }
+ }
@Test
public void shouldReturnOkWhenHealthy() throws Exception {
@@ -63,6 +91,17 @@
assertCheckResult(respPayload, JGIT, "passed");
}
+ @Test
+ public void shouldReturnQueryChangesCheck() throws Exception {
+ createChange("refs/for/master");
+ RestResponse resp = getHealthCheckStatus();
+ resp.assertOK();
+
+ JsonObject respPayload = gson.fromJson(resp.getReader(), JsonObject.class);
+
+ assertCheckResult(respPayload, QUERYCHANGES, "passed");
+ }
+
private RestResponse getHealthCheckStatus() throws IOException {
return adminRestSession.get("/config/server/healthcheck~status");
}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckStatusEndpointTest.java b/src/test/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckStatusEndpointTest.java
index 84ec773..4bc63ba 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckStatusEndpointTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckStatusEndpointTest.java
@@ -15,37 +15,55 @@
package com.googlesource.gerrit.plugins.healthcheck;
import static com.google.common.truth.Truth.assertThat;
+import static com.googlesource.gerrit.plugins.healthcheck.HealthCheckConfig.DEFAULT_CONFIG;
+import com.google.common.util.concurrent.MoreExecutors;
import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.extensions.restapi.Response;
+import com.google.gerrit.metrics.DisabledMetricMaker;
+import com.google.gerrit.metrics.MetricMaker;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.googlesource.gerrit.plugins.healthcheck.api.HealthCheckStatusEndpoint;
+import com.googlesource.gerrit.plugins.healthcheck.check.AbstractHealthCheck;
import com.googlesource.gerrit.plugins.healthcheck.check.HealthCheck;
+import com.googlesource.gerrit.plugins.healthcheck.check.MetricsHandler;
+import java.util.concurrent.Executors;
import javax.servlet.http.HttpServletResponse;
import org.junit.Test;
public class HealthCheckStatusEndpointTest {
- public static class TestHealthCheck implements HealthCheck {
- private final HealthCheck.Status checkResult;
- private final String checkName;
+ public static class TestHealthCheck extends AbstractHealthCheck {
+ private final HealthCheck.Result checkResult;
+ private final long sleep;
- public TestHealthCheck(String checkName, HealthCheck.Result result, long ts, long elapsed) {
- this.checkName = checkName;
- this.checkResult = new Status(result, ts, elapsed);
+ public TestHealthCheck(
+ HealthCheckConfig config, String checkName, HealthCheck.Result result, long sleep) {
+ super(
+ MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10)),
+ config,
+ checkName,
+ new MetricsHandler.Factory() {
+
+ @Override
+ public MetricsHandler create(String name) {
+ return new MetricsHandler(checkName, new DisabledMetricMaker());
+ }
+ });
+ this.checkResult = result;
+ this.sleep = sleep;
}
@Override
- public Status run() {
+ public Result doCheck() {
+ try {
+ Thread.sleep(sleep);
+ } catch (InterruptedException e) {
+ }
return checkResult;
}
-
- @Override
- public String name() {
- return checkName;
- }
}
@Test
@@ -56,7 +74,11 @@
@Override
protected void configure() {
DynamicSet.bind(binder(), HealthCheck.class)
- .toInstance(new TestHealthCheck("checkOk", HealthCheck.Result.PASSED, 1, 2));
+ .toInstance(
+ new TestHealthCheck(
+ DEFAULT_CONFIG, "checkOk", HealthCheck.Result.PASSED, 0));
+ bind(HealthCheckConfig.class).toInstance(DEFAULT_CONFIG);
+ DynamicSet.bind(binder(), MetricMaker.class).toInstance(new DisabledMetricMaker());
}
});
@@ -68,6 +90,29 @@
}
@Test
+ public void shouldReturnServerErrorWhenOneChecksTimesOut() throws Exception {
+ Injector injector =
+ testInjector(
+ new AbstractModule() {
+ @Override
+ protected void configure() {
+ HealthCheckConfig config =
+ new HealthCheckConfig("[healthcheck]\n" + "timeout = 20");
+ DynamicSet.bind(binder(), HealthCheck.class)
+ .toInstance(
+ new TestHealthCheck(config, "checkOk", HealthCheck.Result.PASSED, 30));
+ bind(HealthCheckConfig.class).toInstance(config);
+ }
+ });
+
+ HealthCheckStatusEndpoint healthCheckApi =
+ injector.getInstance(HealthCheckStatusEndpoint.class);
+ Response<?> resp = (Response<?>) healthCheckApi.apply(null);
+
+ assertThat(resp.statusCode()).isEqualTo(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ }
+
+ @Test
public void shouldReturnServerErrorWhenAtLeastOneCheckIsFailing() throws Exception {
Injector injector =
testInjector(
@@ -75,9 +120,13 @@
@Override
protected void configure() {
DynamicSet.bind(binder(), HealthCheck.class)
- .toInstance(new TestHealthCheck("checkOk", HealthCheck.Result.PASSED, 1, 2));
+ .toInstance(
+ new TestHealthCheck(
+ DEFAULT_CONFIG, "checkOk", HealthCheck.Result.PASSED, 0));
DynamicSet.bind(binder(), HealthCheck.class)
- .toInstance(new TestHealthCheck("checkKo", HealthCheck.Result.FAILED, 1, 2));
+ .toInstance(
+ new TestHealthCheck(
+ DEFAULT_CONFIG, "checkKo", HealthCheck.Result.FAILED, 0));
}
});
diff --git a/src/test/java/com/googlesource/gerrit/plugins/healthcheck/JGitHealthCheckTest.java b/src/test/java/com/googlesource/gerrit/plugins/healthcheck/JGitHealthCheckTest.java
index 990b4cb..6e78dfe 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/healthcheck/JGitHealthCheckTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/healthcheck/JGitHealthCheckTest.java
@@ -15,9 +15,11 @@
package com.googlesource.gerrit.plugins.healthcheck;
import static com.google.common.truth.Truth.assertThat;
+import static com.googlesource.gerrit.plugins.healthcheck.HealthCheckConfig.DEFAULT_CONFIG;
import static org.eclipse.jgit.lib.RefUpdate.Result.NEW;
import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.gerrit.metrics.DisabledMetricMaker;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.git.GitRepositoryManager;
@@ -27,6 +29,7 @@
import com.google.inject.Inject;
import com.googlesource.gerrit.plugins.healthcheck.check.HealthCheck.Result;
import com.googlesource.gerrit.plugins.healthcheck.check.JGitHealthCheck;
+import com.googlesource.gerrit.plugins.healthcheck.check.MetricsHandler;
import java.io.IOException;
import java.util.Collections;
import java.util.SortedSet;
@@ -45,6 +48,13 @@
private AllProjectsName allProjectsName = new AllProjectsName("All-Projects");
private InMemoryRepositoryManager inMemoryRepositoryManager = new InMemoryRepositoryManager();
private PersonIdent personIdent = new PersonIdent("Gerrit Rietveld", "gerrit@rietveld.nl");
+ private final MetricsHandler.Factory metricsHandlerFactory =
+ new MetricsHandler.Factory() {
+ @Override
+ public MetricsHandler create(String name) {
+ return new MetricsHandler("foo", new DisabledMetricMaker());
+ }
+ };
@Inject private ListeningExecutorService executor;
@@ -60,14 +70,24 @@
@Test
public void shouldBeHealthyWhenJGitIsWorking() {
JGitHealthCheck reviewDbCheck =
- new JGitHealthCheck(executor, getWorkingRepositoryManager(), allProjectsName);
+ new JGitHealthCheck(
+ executor,
+ DEFAULT_CONFIG,
+ getWorkingRepositoryManager(),
+ allProjectsName,
+ metricsHandlerFactory);
assertThat(reviewDbCheck.run().result).isEqualTo(Result.PASSED);
}
@Test
public void shouldBeUnhealthyWhenJGitIsFailing() {
JGitHealthCheck jGitHealthCheck =
- new JGitHealthCheck(executor, getFailingGitRepositoryManager(), allProjectsName);
+ new JGitHealthCheck(
+ executor,
+ DEFAULT_CONFIG,
+ getFailingGitRepositoryManager(),
+ allProjectsName,
+ metricsHandlerFactory);
assertThat(jGitHealthCheck.run().result).isEqualTo(Result.FAILED);
}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/healthcheck/MetricsHandlerTest.java b/src/test/java/com/googlesource/gerrit/plugins/healthcheck/MetricsHandlerTest.java
new file mode 100644
index 0000000..aa66b1f
--- /dev/null
+++ b/src/test/java/com/googlesource/gerrit/plugins/healthcheck/MetricsHandlerTest.java
@@ -0,0 +1,99 @@
+package com.googlesource.gerrit.plugins.healthcheck;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.gerrit.metrics.Counter0;
+import com.google.gerrit.metrics.Description;
+import com.google.gerrit.metrics.DisabledMetricMaker;
+import com.google.gerrit.metrics.Timer0;
+import com.googlesource.gerrit.plugins.healthcheck.check.HealthCheck.Result;
+import com.googlesource.gerrit.plugins.healthcheck.check.HealthCheck.Status;
+import com.googlesource.gerrit.plugins.healthcheck.check.MetricsHandler;
+import java.util.concurrent.TimeUnit;
+import org.junit.Test;
+
+public class MetricsHandlerTest {
+
+ private class TestMetricsMaker extends DisabledMetricMaker {
+ private Long failures = 0L;
+ private Long latency = 0L;
+
+ @Override
+ public Counter0 newCounter(String name, Description desc) {
+ return new Counter0() {
+ @Override
+ public void incrementBy(long value) {
+ failures += value;
+ }
+
+ @Override
+ public void remove() {}
+ };
+ }
+
+ @Override
+ public Timer0 newTimer(String name, Description desc) {
+ return new Timer0() {
+ @Override
+ public void remove() {}
+
+ @Override
+ public void record(long value, TimeUnit unit) {
+ latency = value;
+ }
+ };
+ }
+ }
+
+ @Test
+ public void shouldSendCounterWhenStatusFailed() {
+ TestMetricsMaker metricMaker = new TestMetricsMaker();
+ MetricsHandler handler = new MetricsHandler("test", metricMaker);
+
+ handler.sendMetrics(new Status(Result.FAILED, 1L, 1L));
+
+ assertThat(metricMaker.failures).isEqualTo(1L);
+ }
+
+ @Test
+ public void shouldSendCounterWhenStatusTimeout() {
+ TestMetricsMaker metricMaker = new TestMetricsMaker();
+ MetricsHandler handler = new MetricsHandler("test", metricMaker);
+
+ handler.sendMetrics(new Status(Result.TIMEOUT, 1L, 1L));
+
+ assertThat(metricMaker.failures).isEqualTo(1L);
+ }
+
+ @Test
+ public void shouldNOTSendCounterWhenStatusSuccess() {
+ TestMetricsMaker metricMaker = new TestMetricsMaker();
+ MetricsHandler handler = new MetricsHandler("test", metricMaker);
+
+ handler.sendMetrics(new Status(Result.PASSED, 1L, 1L));
+
+ assertThat(metricMaker.failures).isEqualTo(0L);
+ }
+
+ @Test
+ public void shouldRecordLatencyWhenSuccess() {
+ TestMetricsMaker metricMaker = new TestMetricsMaker();
+ MetricsHandler handler = new MetricsHandler("test", metricMaker);
+ Long elapsed = System.currentTimeMillis();
+
+ handler.sendMetrics(new Status(Result.PASSED, 1L, elapsed));
+
+ assertThat(metricMaker.latency).isEqualTo(elapsed);
+ }
+
+ @Test
+ public void shouldRecordLatencyWhenFailure() {
+ TestMetricsMaker metricMaker = new TestMetricsMaker();
+ MetricsHandler handler = new MetricsHandler("test", metricMaker);
+ Long elapsed = System.currentTimeMillis();
+
+ handler.sendMetrics(new Status(Result.FAILED, 1L, elapsed));
+
+ assertThat(metricMaker.latency).isEqualTo(elapsed);
+ }
+}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/healthcheck/ProjectsListHealthCheckTest.java b/src/test/java/com/googlesource/gerrit/plugins/healthcheck/ProjectsListHealthCheckTest.java
index a45ea32..f7c52c3 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/healthcheck/ProjectsListHealthCheckTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/healthcheck/ProjectsListHealthCheckTest.java
@@ -15,15 +15,17 @@
package com.googlesource.gerrit.plugins.healthcheck;
import static com.google.common.truth.Truth.assertThat;
+import static com.googlesource.gerrit.plugins.healthcheck.HealthCheckConfig.DEFAULT_CONFIG;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.gerrit.extensions.common.ProjectInfo;
import com.google.gerrit.extensions.restapi.BadRequestException;
+import com.google.gerrit.metrics.DisabledMetricMaker;
import com.google.gerrit.server.project.ListProjects;
import com.google.inject.Guice;
import com.google.inject.Inject;
-import com.googlesource.gerrit.plugins.healthcheck.check.AbstractHealthCheck;
import com.googlesource.gerrit.plugins.healthcheck.check.HealthCheck.Result;
+import com.googlesource.gerrit.plugins.healthcheck.check.MetricsHandler;
import com.googlesource.gerrit.plugins.healthcheck.check.ProjectsListHealthCheck;
import java.util.SortedMap;
import java.util.TreeMap;
@@ -31,24 +33,33 @@
import org.junit.Test;
public class ProjectsListHealthCheckTest {
+ private final MetricsHandler.Factory metricsHandlerFactory =
+ new MetricsHandler.Factory() {
+ @Override
+ public MetricsHandler create(String name) {
+ return new MetricsHandler("foo", new DisabledMetricMaker());
+ }
+ };
@Inject private ListeningExecutorService executor;
@Before
- public void setUp() {
+ public void setUp() throws Exception {
Guice.createInjector(new HealthCheckModule()).injectMembers(this);
}
@Test
public void shouldBeHealthyWhenListProjectsWorks() {
ProjectsListHealthCheck jGitHealthCheck =
- new ProjectsListHealthCheck(executor, getWorkingProjectList(0));
+ new ProjectsListHealthCheck(
+ executor, DEFAULT_CONFIG, getWorkingProjectList(0), metricsHandlerFactory);
assertThat(jGitHealthCheck.run().result).isEqualTo(Result.PASSED);
}
@Test
public void shouldBeUnhealthyWhenListProjectsIsFailing() {
ProjectsListHealthCheck jGitHealthCheck =
- new ProjectsListHealthCheck(executor, getFailingProjectList());
+ new ProjectsListHealthCheck(
+ executor, DEFAULT_CONFIG, getFailingProjectList(), metricsHandlerFactory);
assertThat(jGitHealthCheck.run().result).isEqualTo(Result.FAILED);
}
@@ -56,7 +67,10 @@
public void shouldBeUnhealthyWhenListProjectsIsTimingOut() {
ProjectsListHealthCheck jGitHealthCheck =
new ProjectsListHealthCheck(
- executor, getWorkingProjectList(AbstractHealthCheck.CHECK_TIMEOUT * 2));
+ executor,
+ DEFAULT_CONFIG,
+ getWorkingProjectList(DEFAULT_CONFIG.getTimeout() * 2),
+ metricsHandlerFactory);
assertThat(jGitHealthCheck.run().result).isEqualTo(Result.TIMEOUT);
}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/healthcheck/ReviewDbHealthCheckTest.java b/src/test/java/com/googlesource/gerrit/plugins/healthcheck/ReviewDbHealthCheckTest.java
index 1e5d712..fc818b7 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/healthcheck/ReviewDbHealthCheckTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/healthcheck/ReviewDbHealthCheckTest.java
@@ -15,41 +15,56 @@
package com.googlesource.gerrit.plugins.healthcheck;
import static com.google.common.truth.Truth.assertThat;
+import static com.googlesource.gerrit.plugins.healthcheck.HealthCheckConfig.DEFAULT_CONFIG;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.gerrit.lifecycle.LifecycleManager;
+import com.google.gerrit.metrics.DisabledMetricMaker;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.testutil.DisabledReviewDb;
import com.google.gerrit.testutil.InMemoryDatabase;
import com.google.gwtorm.server.SchemaFactory;
import com.google.inject.Guice;
import com.google.inject.Inject;
+import com.google.inject.Injector;
import com.googlesource.gerrit.plugins.healthcheck.check.HealthCheck;
+import com.googlesource.gerrit.plugins.healthcheck.check.MetricsHandler;
import com.googlesource.gerrit.plugins.healthcheck.check.ReviewDbHealthCheck;
import org.junit.Before;
import org.junit.Test;
public class ReviewDbHealthCheckTest {
private SchemaFactory<ReviewDb> workingReviewDbFactory;
-
+ private final MetricsHandler.Factory metricsHandlerFactory =
+ new MetricsHandler.Factory() {
+ @Override
+ public MetricsHandler create(String name) {
+ return new MetricsHandler("foo", new DisabledMetricMaker());
+ }
+ };
@Inject private ListeningExecutorService executor;
@Before
public void setUp() throws Exception {
- Guice.createInjector(new HealthCheckModule()).injectMembers(this);
+ Injector testInjector = Guice.createInjector(new HealthCheckModule());
+ testInjector.injectMembers(this);
+
workingReviewDbFactory = InMemoryDatabase.newDatabase(new LifecycleManager()).create();
}
@Test
public void shouldBeHealthyWhenReviewDbIsWorking() {
- ReviewDbHealthCheck reviewDbCheck = new ReviewDbHealthCheck(executor, workingReviewDbFactory);
+ ReviewDbHealthCheck reviewDbCheck =
+ new ReviewDbHealthCheck(
+ executor, DEFAULT_CONFIG, workingReviewDbFactory, metricsHandlerFactory);
assertThat(reviewDbCheck.run().result).isEqualTo(HealthCheck.Result.PASSED);
}
@Test
public void shouldBeUnhealthyWhenReviewDbIsFailing() {
ReviewDbHealthCheck reviewDbCheck =
- new ReviewDbHealthCheck(executor, getFailingReviewDbProvider());
+ new ReviewDbHealthCheck(
+ executor, DEFAULT_CONFIG, getFailingReviewDbProvider(), metricsHandlerFactory);
assertThat(reviewDbCheck.run().result).isEqualTo(HealthCheck.Result.FAILED);
}