Einführung in Dropwizard-Metriken

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.