Created
February 16, 2021 12:18
-
-
Save wpik/871ba8903456eddbcc387c941206b930 to your computer and use it in GitHub Desktop.
External system metrics with micrometer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package p; | |
import feign.FeignException; | |
import io.micrometer.core.instrument.MeterRegistry; | |
import io.micrometer.core.instrument.Timer; | |
import org.springframework.util.Assert; | |
import java.util.Arrays; | |
import java.util.Objects; | |
import java.util.function.Supplier; | |
import static p.SystemResponseMetrics.Outcome.FAILURE; | |
import static p.SystemResponseMetrics.Outcome.SUCCESS; | |
public class SystemResponseMetrics<E extends Enum> { | |
private static final String RESPONSE_TIMER_SUFFIX = ".response.time"; | |
private static final String OPERATION = "operation"; | |
private static final String OUTCOME = "outcome"; | |
private static final String HTTP_STATUS = "http.status"; | |
private final MeterRegistry meterRegistry; | |
private final String system; | |
private final String timerName; | |
private final double[] percentiles; | |
public SystemResponseMetrics(MeterRegistry meterRegistry, String system, Class<E> operations) { | |
this(meterRegistry, system, operations, 0.5, 0.9, 0.95); | |
} | |
public SystemResponseMetrics(MeterRegistry meterRegistry, String system, | |
Class<E> operations, double... percentiles) { | |
Objects.requireNonNull(meterRegistry); | |
Assert.hasLength(system, "System cannot be empty"); | |
Objects.requireNonNull(operations); | |
this.meterRegistry = meterRegistry; | |
this.system = system; | |
this.timerName = system.toLowerCase() + RESPONSE_TIMER_SUFFIX; | |
this.percentiles = percentiles; | |
Arrays.stream(operations.getEnumConstants()) | |
.map(Enum::name) | |
.map(String::toLowerCase) | |
.forEach(this::registerTimer); | |
} | |
private void registerTimer(String operation) { | |
Timer.builder(timerName) | |
.description(system + " response time") | |
.publishPercentiles(percentiles) | |
.tag(OPERATION, operation) | |
.tag(OUTCOME, SUCCESS.getLowerCaseValue()) | |
.tag(HTTP_STATUS, "200") | |
.register(meterRegistry); | |
} | |
public Timer.Sample startTimer() { | |
return Timer.start(meterRegistry); | |
} | |
public void stopResponseTimer(Timer.Sample sample, E operation, Outcome outcome, int httpStatus) { | |
sample.stop(meterRegistry.timer(timerName, | |
OPERATION, operation.name().toLowerCase(), | |
OUTCOME, outcome.getLowerCaseValue(), | |
HTTP_STATUS, Integer.toString(httpStatus))); | |
} | |
public void timeExecution(E operationId, Runnable functionToTime) { | |
timeExecution(operationId, 200, 999, functionToTime); | |
} | |
public <T> T timeExecution(E operationId, Supplier<T> functionToTime) { | |
return timeExecution(operationId, 200, 999, functionToTime); | |
} | |
public void timeExecution(E operationId, int successStatus, int unknownStatus, Runnable functionToTime) { | |
timeExecution(operationId, successStatus, unknownStatus, () -> { | |
functionToTime.run(); | |
return null; | |
}); | |
} | |
public <T> T timeExecution(E operationId, int successStatus, int unknownStatus, Supplier<T> functionToTime) { | |
Timer.Sample sample = startTimer(); | |
try { | |
T result = functionToTime.get(); | |
stopResponseTimer(sample, operationId, SUCCESS, successStatus); | |
return result; | |
} catch (FeignException e) { | |
stopResponseTimer(sample, operationId, FAILURE, e.status()); | |
throw e; | |
} catch (Throwable e) { | |
stopResponseTimer(sample, operationId, FAILURE, unknownStatus); | |
throw e; | |
} | |
} | |
public enum Outcome { | |
SUCCESS, | |
FAILURE; | |
private String lowerCaseValue = name().toLowerCase(); | |
String getLowerCaseValue() { | |
return lowerCaseValue; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment