Einführung in Dropwizard-Metriken
1. Einführung
Metrics ist eine Java-Bibliothek, die Messinstrumente für Java-Anwendungen bereitstellt.
Es enthält mehrere Module. In diesem Artikel werden das Kernmodul für Metriken, das Modul für Metriken-Integritätsprüfungen, das Modul für Metriken-Servlets und das Modul für Metriken-Servlets erläutert und der Rest als Referenz skizziert.
2. Modulmetrics-core
2.1. Maven-Abhängigkeiten
Um das Modulmetrics-core zu verwenden, ist nur eine Abhängigkeit erforderlich, die der Dateipom.xmlhinzugefügt werden muss:
io.dropwizard.metrics
metrics-core
3.1.2
Und Sie können die neueste Versionhere finden.
2.2. MetricRegistry
Einfach ausgedrückt, verwenden wir dieMetricRegistry-Klasse, um eine oder mehrere Metriken zu registrieren.
Wir können eine Metrikregistrierung für alle unsere Metriken verwenden. Wenn wir jedoch unterschiedliche Berichtsmethoden für verschiedene Metriken verwenden möchten, können wir unsere Metriken auch in Gruppen unterteilen und für jede Gruppe unterschiedliche Metrikregistrierungen verwenden.
Erstellen wir jetzt einMetricRegistry:
MetricRegistry metricRegistry = new MetricRegistry();
Und dann können wir einige Metriken mit diesenMetricRegistry registrieren:
Meter meter1 = new Meter();
metricRegistry.register("meter1", meter1);
Meter meter2 = metricRegistry.meter("meter2");
Es gibt zwei grundlegende Möglichkeiten, eine neue Metrik zu erstellen: eine selbst instanziieren oder eine aus der Metrikregistrierung abrufen. Wie Sie sehen können, haben wir beide im obigen Beispiel verwendet. Wir instanziieren dasMeter-Objekt "meter1" und wir erhalten ein weiteresMeter-Objekt "meter2", das durchmetricRegistryerstellt wird ) s.
In einer Metrikregistrierung hat jede Metrik einen eindeutigen Namen, da wir oben „meter1“ und „meter2“ als Metriknamen verwendet haben. MetricRegistry bietet auch eine Reihe statischer Hilfsmethoden, mit denen wir die richtigen Metriknamen erstellen können:
String name1 = MetricRegistry.name(Filter.class, "request", "count");
String name2 = MetricRegistry.name("CustomFilter", "response", "count");
Wenn wir eine Reihe von Metrikregistern verwalten müssen, können wir die KlasseSharedMetricRegistriesverwenden, die singleton- und threadsicher ist. Wir können ein Metrikregister hinzufügen, dieses Metrikregister daraus abrufen und entfernen:
SharedMetricRegistries.add("default", metricRegistry);
MetricRegistry retrievedMetricRegistry = SharedMetricRegistries.getOrCreate("default");
SharedMetricRegistries.remove("default");
3. Metrikkonzepte
Das Metrik-Kern-Modul bietet mehrere häufig verwendete Metriktypen:Meter,Gauge,Counter,Histogram undTimer undReporter für die Ausgabe Metrikwerte.
3.1. Meter
AMetermisst die Anzahl und Rate der Ereignisse:
Meter meter = new Meter();
long initCount = meter.getCount();
assertThat(initCount, equalTo(0L));
meter.mark();
assertThat(meter.getCount(), equalTo(1L));
meter.mark(20);
assertThat(meter.getCount(), equalTo(21L));
double meanRate = meter.getMeanRate();
double oneMinRate = meter.getOneMinuteRate();
double fiveMinRate = meter.getFiveMinuteRate();
double fifteenMinRate = meter.getFifteenMinuteRate();
Die MethodegetCount() gibt die Anzahl der Ereignisereignisse zurück, und die Methodemark()addiert 1 oder n zur Anzahl der Ereignisereignisse. Das ObjektMeterliefert vier Raten, die Durchschnittsraten für die gesamte Lebensdauer vonMeterfür die letzte Minute, für die letzten fünf Minuten bzw. für das letzte Quartal darstellen.
3.2. Gauge
Gauge ist eine Schnittstelle, die einfach verwendet wird, um einen bestimmten Wert zurückzugeben. Das Metrik-Kern-Modul bietet mehrere Implementierungen davon:RatioGauge,CachedGauge,DerivativeGauge undJmxAttributeGauge.
RatioGauge ist eine abstrakte Klasse und misst das Verhältnis eines Wertes zu einem anderen.
Mal sehen, wie man es benutzt. Zuerst implementieren wir eine KlasseAttendanceRatioGauge:
public class AttendanceRatioGauge extends RatioGauge {
private int attendanceCount;
private int courseCount;
@Override
protected Ratio getRatio() {
return Ratio.of(attendanceCount, courseCount);
}
// standard constructors
}
Und dann testen wir es:
RatioGauge ratioGauge = new AttendanceRatioGauge(15, 20);
assertThat(ratioGauge.getValue(), equalTo(0.75));
CachedGauge ist eine weitere abstrakte Klasse, die Werte zwischenspeichern kann. Daher ist es sehr nützlich, wenn die Berechnung der Werte teuer ist. Um es zu verwenden, müssen wir eine KlasseActiveUsersGauge implementieren:
public class ActiveUsersGauge extends CachedGauge> {
@Override
protected List loadValue() {
return getActiveUserCount();
}
private List getActiveUserCount() {
List result = new ArrayList();
result.add(12L);
return result;
}
// standard constructors
}
Dann testen wir es, um zu sehen, ob es wie erwartet funktioniert:
Gauge> activeUsersGauge = new ActiveUsersGauge(15, TimeUnit.MINUTES);
List expected = new ArrayList<>();
expected.add(12L);
assertThat(activeUsersGauge.getValue(), equalTo(expected));
Wir setzen die Ablaufzeit des Caches auf 15 Minuten, wenn wir dieActiveUsersGauge instanziieren.
DerivativeGauge ist ebenfalls eine abstrakte Klasse und ermöglicht es Ihnen, einen Wert von anderenGauge als Wert abzuleiten.
Schauen wir uns ein Beispiel an:
public class ActiveUserCountGauge extends DerivativeGauge, Integer> {
@Override
protected Integer transform(List value) {
return value.size();
}
// standard constructors
}
DiesesGauge leitet seinen Wert von einemActiveUsersGauge ab, daher erwarten wir, dass es der Wert aus der Größe der Basisliste ist:
Gauge> activeUsersGauge = new ActiveUsersGauge(15, TimeUnit.MINUTES);
Gauge activeUserCountGauge = new ActiveUserCountGauge(activeUsersGauge);
assertThat(activeUserCountGauge.getValue(), equalTo(1));
JmxAttributeGauge wird verwendet, wenn wir über JMX auf die Metriken anderer Bibliotheken zugreifen müssen.
3.3. Counter
DasCounter wird zum Aufzeichnen von Inkrementierungen und Dekrementierungen verwendet:
Counter counter = new Counter();
long initCount = counter.getCount();
assertThat(initCount, equalTo(0L));
counter.inc();
assertThat(counter.getCount(), equalTo(1L));
counter.inc(11);
assertThat(counter.getCount(), equalTo(12L));
counter.dec();
assertThat(counter.getCount(), equalTo(11L));
counter.dec(6);
assertThat(counter.getCount(), equalTo(5L));
3.4. Histogram
Histogram wird verwendet, um einen Strom vonLong-Werten zu verfolgen, und analysiert deren statistische Eigenschaften wiemax, min, mean, median, standard deviation, 75th percentile usw.:
Histogram histogram = new Histogram(new UniformReservoir());
histogram.update(5);
long count1 = histogram.getCount();
assertThat(count1, equalTo(1L));
Snapshot snapshot1 = histogram.getSnapshot();
assertThat(snapshot1.getValues().length, equalTo(1));
assertThat(snapshot1.getValues()[0], equalTo(5L));
histogram.update(20);
long count2 = histogram.getCount();
assertThat(count2, equalTo(2L));
Snapshot snapshot2 = histogram.getSnapshot();
assertThat(snapshot2.getValues().length, equalTo(2));
assertThat(snapshot2.getValues()[1], equalTo(20L));
assertThat(snapshot2.getMax(), equalTo(20L));
assertThat(snapshot2.getMean(), equalTo(12.5));
assertEquals(10.6, snapshot2.getStdDev(), 0.1);
assertThat(snapshot2.get75thPercentile(), equalTo(20.0));
assertThat(snapshot2.get999thPercentile(), equalTo(20.0));
Histogram tastet die Daten mithilfe der Reservoir-Abtastung ab. Wenn wir einHistogram-Objekt instanziieren, müssen wir sein Reservoir explizit festlegen.
Reservoir ist eine Schnittstelle und der Metrikkern bietet vier Implementierungen davon:ExponentiallyDecayingReservoir,UniformReservoir,SlidingTimeWindowReservoir,SlidingWindowReservoir.
Im obigen Abschnitt haben wir erwähnt, dass eine Metrik neben der Verwendung eines Konstruktors. auch vonMetricRegistry, erstellt werden kann. Wenn wirmetricRegistry.histogram() verwenden, wird eineHistogram-Instanz mitExponentiallyDecayingReservoir Implementierung.
3.5. Timer
Timer wird verwendet, um mehrere Zeitdauern zu verfolgen, die durchContext Objekte dargestellt werden, und liefert auch deren statistische Daten:
Timer timer = new Timer();
Timer.Context context1 = timer.time();
TimeUnit.SECONDS.sleep(5);
long elapsed1 = context1.stop();
assertEquals(5000000000L, elapsed1, 1000000);
assertThat(timer.getCount(), equalTo(1L));
assertEquals(0.2, timer.getMeanRate(), 0.1);
Timer.Context context2 = timer.time();
TimeUnit.SECONDS.sleep(2);
context2.close();
assertThat(timer.getCount(), equalTo(2L));
assertEquals(0.3, timer.getMeanRate(), 0.1);
3.6. Reporter
Wenn wir unsere Messungen ausgeben müssen, können wirReporter verwenden. Dies ist eine Schnittstelle, und das Metrik-Kern-Modul bietet verschiedene Implementierungen davon, wieConsoleReporter,CsvReporter,Slf4jReporter,JmxReporter und so weiter.
Hier verwenden wirConsoleReporter als Beispiel:
MetricRegistry metricRegistry = new MetricRegistry();
Meter meter = metricRegistry.meter("meter");
meter.mark();
meter.mark(200);
Histogram histogram = metricRegistry.histogram("histogram");
histogram.update(12);
histogram.update(17);
Counter counter = metricRegistry.counter("counter");
counter.inc();
counter.dec();
ConsoleReporter reporter = ConsoleReporter.forRegistry(metricRegistry).build();
reporter.start(5, TimeUnit.MICROSECONDS);
reporter.report();
Hier ist die Beispielausgabe vonConsoleReporter:
-- Histograms ------------------------------------------------------------------
histogram
count = 2
min = 12
max = 17
mean = 14.50
stddev = 2.50
median = 17.00
75% <= 17.00
95% <= 17.00
98% <= 17.00
99% <= 17.00
99.9% <= 17.00
-- Meters ----------------------------------------------------------------------
meter
count = 201
mean rate = 1756.87 events/second
1-minute rate = 0.00 events/second
5-minute rate = 0.00 events/second
15-minute rate = 0.00 events/second
4. Modulmetrics-healthchecks
Metrics verfügt über ein Erweiterungsmodul für Metrics-Healthchecks zum Behandeln von Integritätsprüfungen.
4.1. Maven-Abhängigkeiten
Um das Metrics-Healthchecks-Modul zu verwenden, müssen wir diese Abhängigkeit zurpom.xml-Datei hinzufügen:
io.dropwizard.metrics
metrics-healthchecks
3.1.2
Und Sie können die neueste Versionhere finden.
4.2. Verwendungszweck
Erstens benötigen wir mehrere Klassen, die für bestimmte Integritätsprüfungsvorgänge verantwortlich sind, und diese Klassen müssenHealthCheck implementieren.
Zum Beispiel verwenden wirDatabaseHealthCheck undUserCenterHealthCheck:
public class DatabaseHealthCheck extends HealthCheck {
@Override
protected Result check() throws Exception {
return Result.healthy();
}
}
public class UserCenterHealthCheck extends HealthCheck {
@Override
protected Result check() throws Exception {
return Result.healthy();
}
}
Dann brauchen wir einHealthCheckRegistry (das genau wieMetricRegistry ist) und registrieren dieDatabaseHealthCheck undUserCenterHealthCheck damit:
HealthCheckRegistry healthCheckRegistry = new HealthCheckRegistry();
healthCheckRegistry.register("db", new DatabaseHealthCheck());
healthCheckRegistry.register("uc", new UserCenterHealthCheck());
assertThat(healthCheckRegistry.getNames().size(), equalTo(2));
Wir können auch die Registrierung derHealthCheck aufheben:
healthCheckRegistry.unregister("uc");
assertThat(healthCheckRegistry.getNames().size(), equalTo(1));
Wir können alleHealthCheck-Instanzen ausführen:
Map results = healthCheckRegistry.runHealthChecks();
for (Map.Entry entry : results.entrySet()) {
assertThat(entry.getValue().isHealthy(), equalTo(true));
}
Schließlich können wir eine bestimmteHealthCheck-Instanz ausführen:
healthCheckRegistry.runHealthCheck("db");
5. Modulmetrics-servlets
Metriken bieten uns eine Handvoll nützlicher Servlets, mit denen wir über HTTP-Anforderungen auf metrikenbezogene Daten zugreifen können.
5.1. Maven-Abhängigkeiten
Um das Metrics-Servlets-Modul zu verwenden, müssen wir diese Abhängigkeit zur Dateipom.xmlhinzufügen:
io.dropwizard.metrics
metrics-servlets
3.1.2
Und Sie können die neueste Versionhere finden.
5.2. HealthCheckServlet Verwendung
HealthCheckServlet liefert Ergebnisse der Gesundheitsprüfung. Zuerst müssen wir einServletContextListener erstellen, das unserHealthCheckRegistry verfügbar macht:
public class MyHealthCheckServletContextListener
extends HealthCheckServlet.ContextListener {
public static HealthCheckRegistry HEALTH_CHECK_REGISTRY
= new HealthCheckRegistry();
static {
HEALTH_CHECK_REGISTRY.register("db", new DatabaseHealthCheck());
}
@Override
protected HealthCheckRegistry getHealthCheckRegistry() {
return HEALTH_CHECK_REGISTRY;
}
}
Dann fügen wir sowohl diesen Listener als auchHealthCheckServlet in die Dateiweb.xml ein:
com.example.metrics.servlets.MyHealthCheckServletContextListener
healthCheck
com.codahale.metrics.servlets.HealthCheckServlet
healthCheck
/healthcheck
Jetzt können wir die Webanwendung starten und eine GET-Anforderung an "http: // localhost: 8080 / healthcheck" senden, um die Ergebnisse der Integritätsprüfung abzurufen. Die Antwort sollte folgendermaßen aussehen:
{
"db": {
"healthy": true
}
}
5.3. ThreadDumpServlet Verwendung
ThreadDumpServlet bietet Informationen zu allen Live-Threads in der JVM, ihren Status, ihren Stack-Traces und dem Status aller Sperren, auf die sie möglicherweise warten. Wenn wir es verwenden möchten, müssen wir diese einfach in dieweb.xml-Datei einfügen:
threadDump
com.codahale.metrics.servlets.ThreadDumpServlet
threadDump
/threaddump
Thread-Dump-Daten sind unter "http: // localhost: 8080 / threaddump" verfügbar.
5.4. PingServlet Verwendung
PingServlet kann verwendet werden, um zu testen, ob die Anwendung ausgeführt wird. Wir fügen diese in dieweb.xml-Datei ein:
ping
com.codahale.metrics.servlets.PingServlet
ping
/ping
Senden Sie anschließend eine GET-Anforderung an "http: // localhost: 8080 / ping". Der Statuscode der Antwort lautet 200 und der Inhalt lautet "Pong".
5.5. MetricsServlet Verwendung
MetricsServlet liefert Metrikdaten. Zuerst müssen wir einServletContextListener erstellen, das unserMetricRegistry verfügbar macht:
public class MyMetricsServletContextListener
extends MetricsServlet.ContextListener {
private static MetricRegistry METRIC_REGISTRY
= new MetricRegistry();
static {
Counter counter = METRIC_REGISTRY.counter("m01-counter");
counter.inc();
Histogram histogram = METRIC_REGISTRY.histogram("m02-histogram");
histogram.update(5);
histogram.update(20);
histogram.update(100);
}
@Override
protected MetricRegistry getMetricRegistry() {
return METRIC_REGISTRY;
}
}
Sowohl dieser Listener als auchMetricsServlet müssen zuweb.xml hinzugefügt werden:
com.codahale.metrics.servlets.MyMetricsServletContextListener
metrics
com.codahale.metrics.servlets.MetricsServlet
metrics
/metrics
Dies wird in unserer Webanwendung unter "http: // localhost: 8080 / metrics" angezeigt. Die Antwort sollte verschiedene Messdaten enthalten:
{
"version": "3.0.0",
"gauges": {},
"counters": {
"m01-counter": {
"count": 1
}
},
"histograms": {
"m02-histogram": {
"count": 3,
"max": 100,
"mean": 41.66666666666666,
"min": 5,
"p50": 20,
"p75": 100,
"p95": 100,
"p98": 100,
"p99": 100,
"p999": 100,
"stddev": 41.69998667732268
}
},
"meters": {},
"timers": {}
}
5.6. AdminServlet Verwendung
AdminServlet aggregiertHealthCheckServlet,ThreadDumpServlet,MetricsServlet undPingServlet.
Fügen wir diese zuweb.xml hinzu:
admin
com.codahale.metrics.servlets.AdminServlet
admin
/admin/*
Sie können jetzt unter "http: // localhost: 8080 / admin" darauf zugreifen. Wir erhalten eine Seite mit vier Links, einen für jedes dieser vier Servlets.
Beachten Sie, dass für die Integritätsprüfung und den Zugriff auf Metrikdaten diese beiden Listener weiterhin benötigt werden.
6. Modulmetrics-servlet
Das Modulmetrics-servlet bietet einFilter mit mehreren Metriken: Messgeräte für Statuscodes, ein Zähler für die Anzahl der aktiven Anforderungen und ein Zeitgeber für die Anforderungsdauer.
6.1. Maven-Abhängigkeiten
Um dieses Modul zu verwenden, fügen wir zunächst die Abhängigkeit zupom.xml hinzu:
io.dropwizard.metrics
metrics-servlet
3.1.2
Und Sie können die neueste Versionhere finden.
6.2. Verwendungszweck
Um es zu verwenden, müssen wir einServletContextListener erstellen, das unserMetricRegistry demInstrumentedFilter aussetzt:
public class MyInstrumentedFilterContextListener
extends InstrumentedFilterContextListener {
public static MetricRegistry REGISTRY = new MetricRegistry();
@Override
protected MetricRegistry getMetricRegistry() {
return REGISTRY;
}
}
Dann addieren wir diese zuweb.xml:
com.example.metrics.servlet.MyInstrumentedFilterContextListener
instrumentFilter
com.codahale.metrics.servlet.InstrumentedFilter
instrumentFilter
/*
Jetzt können dieInstrumentedFilter funktionieren. Wenn wir auf seine Metrikdaten zugreifen möchten, können wir dies überMetricRegistryREGISTRY tun.
7. Andere Module
Mit Ausnahme der oben vorgestellten Module verfügt Metrics über einige andere Module für verschiedene Zwecke:
-
metrics-jvm: Bietet mehrere nützliche Metriken für die Instrumentierung von JVM-Interna
-
metrics-ehcache: StelltInstrumentedEhcache bereit, einen Dekorator für Ehcache-Caches
-
metrics-httpclient: Stellt Klassen für die Instrumentierung von Apache HttpClient (4.x-Version) bereit.
-
metrics-log4j: StelltInstrumentedAppender bereit, eine Implementierung von Log4jAppenderfür log4j 1.x, die die Rate der protokollierten Ereignisse anhand ihrer Protokollierungsstufe aufzeichnet
-
metrics-log4j2: ähnelt metrisch-log4j, nur für log4j 2.x.
-
metrics-logback: StelltInstrumentedAppender bereit, eine Implementierung von LogbackAppender, die die Rate der protokollierten Ereignisse anhand ihrer Protokollierungsstufe aufzeichnet
-
metrics-json: liefertHealthCheckModule undMetricsModule für Jackson
Abgesehen von diesen Hauptprojektmodulen bieten einige anderethird party librarieseine Integration mit anderen Bibliotheken und Frameworks.
8. Fazit
Die Instrumentierung von Anwendungen ist eine häufige Anforderung. Daher haben wir in diesem Artikel Metriken eingeführt, in der Hoffnung, dass sie Ihnen bei der Lösung Ihres Problems helfen können.
Wie immer ist der vollständige Quellcode für das Beispielover on GitHub verfügbar.