Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update origin health-check metric name (fixes #269) #289

Merged
merged 2 commits into from
Sep 18, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,29 @@
package com.hotels.styx.client.healthcheck;

import com.codahale.metrics.Meter;
import com.hotels.styx.client.HttpClient;
import com.hotels.styx.api.FullHttpRequest;
import com.hotels.styx.api.extension.Origin;
import com.hotels.styx.api.MetricRegistry;
import com.hotels.styx.api.extension.Origin;
import com.hotels.styx.client.HttpClient;
import com.hotels.styx.common.SimpleCache;
import io.netty.buffer.ByteBuf;
import rx.Observer;

import static com.hotels.styx.api.HttpHeaderNames.HOST;
import static com.hotels.styx.api.HttpResponseStatus.OK;
import static com.hotels.styx.client.healthcheck.OriginHealthCheckFunction.OriginState.HEALTHY;
import static com.hotels.styx.client.healthcheck.OriginHealthCheckFunction.OriginState.UNHEALTHY;
import static io.netty.util.ReferenceCountUtil.release;
import static java.lang.String.format;
import static java.util.Objects.requireNonNull;

/**
* Health-check that works by making a request to a URL and ensuring that it gets an HTTP 200 OK code back.
*/
public class UrlRequestHealthCheck implements OriginHealthCheckFunction {
private static final MeterFormat DEPRECATED_METER_FORMAT = new MeterFormat("origins.healthcheck.failure.%s");
private static final MeterFormat CORRECTED_METER_FORMAT = new MeterFormat("origins.%s.healthcheck.failure");

private final String healthCheckUri;
private final HttpClient client;
private final SimpleCache<Origin, Meter> meterCache;
private final SimpleCache<Origin, FailureMeter> meterCache;

/**
* Construct an instance.
Expand All @@ -49,7 +50,7 @@ public class UrlRequestHealthCheck implements OriginHealthCheckFunction {
public UrlRequestHealthCheck(String healthCheckUri, HttpClient client, MetricRegistry metricRegistry) {
this.healthCheckUri = uriWithInitialSlash(healthCheckUri);
this.client = requireNonNull(client);
this.meterCache = new SimpleCache<>(origin -> metricRegistry.meter("origins.healthcheck.failure." + origin.applicationId()));
this.meterCache = new SimpleCache<>(origin -> new FailureMeter(origin, metricRegistry));
}

private static String uriWithInitialSlash(String uri) {
Expand Down Expand Up @@ -83,19 +84,32 @@ private FullHttpRequest newHealthCheckRequestFor(Origin origin) {
.build();
}

// Note: this differs from just calling Observable.subscribe with no arguments, because it ignores errors too, whereas subscribe() throws an exception
private static class DoNothingObserver implements Observer<ByteBuf> {
@Override
public void onCompleted() {
private static final class FailureMeter {
private final Meter deprecatedMeter;
private final Meter correctedMeter;

FailureMeter(Origin origin, MetricRegistry metricRegistry) {
this.deprecatedMeter = DEPRECATED_METER_FORMAT.meter(origin, metricRegistry);
this.correctedMeter = CORRECTED_METER_FORMAT.meter(origin, metricRegistry);
}

@Override
public void onError(Throwable throwable) {
void mark() {
deprecatedMeter.mark();
correctedMeter.mark();
}
}

private static final class MeterFormat {
private final String format;

MeterFormat(String format) {
this.format = format;
}

public Meter meter(Origin origin, MetricRegistry metricRegistry) {
String name = format(format, origin.applicationId());

@Override
public void onNext(ByteBuf byteBuf) {
release(byteBuf);
return metricRegistry.meter(name);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,22 @@
*/
package com.hotels.styx.client.healthcheck;

import com.hotels.styx.client.HttpClient;
import com.hotels.styx.api.FullHttpResponse;
import com.hotels.styx.api.extension.Origin;
import com.hotels.styx.api.HttpResponseStatus;
import com.hotels.styx.api.MetricRegistry;
import com.hotels.styx.api.extension.Origin;
import com.hotels.styx.api.metrics.codahale.CodaHaleMetricRegistry;
import com.hotels.styx.client.HttpClient;
import com.hotels.styx.client.healthcheck.OriginHealthCheckFunction.OriginState;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

import java.io.IOException;
import java.util.concurrent.CompletableFuture;

import static com.hotels.styx.api.FullHttpResponse.response;
import static com.hotels.styx.api.extension.Origin.newOriginBuilder;
import static com.hotels.styx.api.HttpResponseStatus.NOT_FOUND;
import static com.hotels.styx.api.HttpResponseStatus.OK;
import static com.hotels.styx.api.extension.Origin.newOriginBuilder;
import static com.hotels.styx.client.healthcheck.OriginHealthCheckFunction.OriginState.HEALTHY;
import static com.hotels.styx.client.healthcheck.OriginHealthCheckFunction.OriginState.UNHEALTHY;
import static org.hamcrest.MatcherAssert.assertThat;
Expand Down Expand Up @@ -66,7 +65,7 @@ public void sendsTheHealthCheckRequestToTheGivenUrl() {
}

@Test
public void declaresOriginHealthyOnOkResponseCode() throws IOException {
public void declaresOriginHealthyOnOkResponseCode() {
HttpClient client = request -> respondWith(OK);

new UrlRequestHealthCheck("/version.txt", client, metricRegistry)
Expand All @@ -77,27 +76,29 @@ public void declaresOriginHealthyOnOkResponseCode() throws IOException {
}

@Test
public void declaresOriginUnhealthyOnNon200Ok() throws IOException {
public void declaresOriginUnhealthyOnNon200Ok() {
HttpClient client = request -> respondWith(NOT_FOUND);

new UrlRequestHealthCheck("/version.txt", client, metricRegistry)
.check(someOrigin, state -> this.originState = state);

assertThat(originState, is(UNHEALTHY));
assertThat(metricRegistry.meter("origins.healthcheck.failure.generic-app").getCount(), is(1L));
assertThat(metricRegistry.getMeters().size(), is(1));
assertThat(metricRegistry.meter("origins.generic-app.healthcheck.failure").getCount(), is(1L));
assertThat(metricRegistry.getMeters().size(), is(2));
}

@Test
public void declaredOriginUnhealthyOnTransportException() throws IOException {
public void declaredOriginUnhealthyOnTransportException() {
HttpClient client = request -> respondWith(new RuntimeException("health check failure, as expected"));

new UrlRequestHealthCheck("/version.txt", client, metricRegistry)
.check(someOrigin, state -> this.originState = state);

assertThat(originState, is(UNHEALTHY));
assertThat(metricRegistry.meter("origins.healthcheck.failure.generic-app").getCount(), is(1L));
assertThat(metricRegistry.getMeters().size(), is(1));
assertThat(metricRegistry.meter("origins.generic-app.healthcheck.failure").getCount(), is(1L));
assertThat(metricRegistry.getMeters().size(), is(2));
}

private static CompletableFuture<FullHttpResponse> respondWith(Throwable error) {
Expand Down
10 changes: 5 additions & 5 deletions docs/user-guide/configure-health-checks.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ into `BackendService`.

A meter of failed health check attempts per backend service:

origins.healthcheck.failure.<BACKEND-ID>.count
origins.healthcheck.failure.<BACKEND-ID>.m1_rate
origins.healthcheck.failure.<BACKEND-ID>.m5_rate
origins.healthcheck.failure.<BACKEND-ID>.m15_rate
origins.healthcheck.failure.<BACKEND-ID>.mean_rate
origins.<BACKEND-ID>.healthcheck.failure.count
origins.<BACKEND-ID>.healthcheck.failure.m1_rate
origins.<BACKEND-ID>.healthcheck.failure.m5_rate
origins.<BACKEND-ID>.healthcheck.failure.m15_rate
origins.<BACKEND-ID>.healthcheck.failure.mean_rate
7 changes: 5 additions & 2 deletions docs/user-guide/metrics.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,11 @@ The server side metrics scopes are illustrated in a diagram below:
origins.<backend>.<origin>.status
```

- Health-check metrics
```
origins.<backend>.healthcheck.failure
```

The client side metrics scopes are illustrated in a diagram below:

![Styx Client Metrics](../assets/styx-origin-metrics.png "Styx client metrics")
Expand Down Expand Up @@ -221,8 +226,6 @@ Styx also measures metrics from the underlying JVM:

Following metrics are subject to change their names:

origins.healthcheck.failure.<app>
origins.healthcheck.failure.<app>.<instance>
origins.response.status.<code>


Expand Down