Skip to content
Permalink
Branch: master
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
593 lines (444 sloc) 20.7 KB

Application Metrics Programming Model

MicroProfile Metrics provides a way to register Application-specific metrics to allow applications to expose metrics in the application scope (see [scopes] for the description of scopes).

Metrics and their metadata are added to a Metric Registry upon definition and can afterwards have their values set and retrieved via the Java-API and also be exposed via the REST-API (see [rest-api]).

Tip
Implementors of this specification can use the Java API to also expose metrics for base and vendor scope by using the respective Metric Registry.

In order to make setting the values easier, Annotations are made available.

Example set-up of a Gauge metric. No unit is given, so MetricUnits.NONE is used, an explicit name is provided
@Gauge(unit = MetricUnits.NONE, name = "queueSize")
public int getQueueSize() {
  return queue.size;
}
Note
The programming API follows Dropwizard Metrics 3.2.3 API, but with local changes. It is expected that many existing DropWizard Metrics based applications can easily be ported over by exchanging the package names.

It will be possible to use the non-annotations API, but using the annotations will generally be easier for developers.

Responsibility of the MicroProfile Metrics implementation

  • The implementation must scan the application at deploy time for Annotations and register the Metrics along with their metadata in the application MetricsRegistry.

  • The implementation must watch the annotated objects and update internal data structures when the values of the annotated objects change.

  • The implementation must expose the values of the objects registered in the MetricsRegistry via REST-API as described in [rest-api].

  • Metrics registered via non-annotations API need their values be set via updates from the application code.

  • The implementation must flag duplicate metrics upon registration and reject the duplicate unless the metric is explicitly marked as reusable upon first registration and in all subsequent registrations.

    • A duplicate metric is a metric that has the same scope and MetricID (name and tags) as an existing one.

    • The implementation must throw an IllegalArgumentException when the metric is rejected.

    • It is not allowed to reuse a metric (name) for metrics of different types. The implementation must throw an IllegalArgumentException if such a mismatch is detected.

    • See reusing of metrics for more details.

  • The implementation must flag and reject metrics upon registration if the metadata information being registered is not equivalent to the metadata information that has already been registered under the given metric name (if it already exists).

    • All metrics of a given metric name must be associated with the same metadata information

    • The implementation must throw an IllegalArgumentException when the metric is rejected.

  • The implementation must throw an IllegalStateException if an annotated metric is invoked, but the metric no longer exists in the MetricRegistry. This applies to the following annotations : @Timed, @Counted, @ConcurrentGauge, @Metered

Base Package

All Java-Classes are in the top-level package org.eclipse.microprofile.metrics or one of its sub-packages.

Tip

The org.eclipse.microprofile.metrics package was influenced by the Drop Wizard Metrics project release 3.2.3.

Implementors can consult this project for implementation ideas.

See [references] for more information.

Annotations

All Annotations are in the org.eclipse.microprofile.metrics.annotation package

Note

These annotations include interceptor bindings as defined by the Java Interceptors specification.

CDI leverages on the Java Interceptors specification to provide the ability to associate interceptors to beans via typesafe interceptor bindings, as a mean to separate cross-cutting concerns, like Metrics annotations instrumentation, from the application business logic.

Both the Java Interceptors and CDI specifications set restrictions about the type of bean to which an interceptor can be bound.

That implies only managed beans whose bean types are proxyable can be instrumented using the Metrics annotations.

Tip

The org.eclipse.microprofile.metrics.annotation package was influenced by the CDI extension for Dropwizard Metric project release 1.4.0.

Implementors can consult this project for implementation ideas.

See [references] for more information.

The following Annotations exist, see below for common fields:

Annotation Applies to Description Default Unit

@Counted

M, C, T

Denotes a counter, which counts the invocations of the annotated object.

MetricUnits.NONE

@ConcurrentGauge

M, C, T

Denotes a gauge which counts the parallel invocations of the annotated object.

MetricUnits.NONE

@Gauge

M

Denotes a gauge, which samples the value of the annotated object.

no default, must be supplied by the user

@Metered

M, C, T

Denotes a meter, which tracks the frequency of invocations of the annotated object.

MetricUnits.PER_SECOND

@Metric

M, F, P

An annotation that contains the metadata information when requesting a metric to be injected or produced. This annotation can be used on fields of type Meter, Timer, Counter, and Histogram. For Gauge, the @Metric annotation can only be used on producer methods/fields.

MetricUnits.NONE

@Timed

M, C, T

Denotes a timer, which tracks duration of the annotated object.

MetricUnits.NANOSECONDS

(C=Constructor, F=Field, M=Method, P=Parameter, T=Type)

Annotation Description Default

@RegistryType

Qualifies the scope of Metric Registry to inject when injecting a MetricRegistry.

application (scope)

Fields

All annotations (Except RegistryType) have the following fields that correspond to the metadata fields described in [meta-data-def].

String name

Optional. Sets the name of the metric. If not explicitly given the name of the annotated object is used.

boolean absolute

If true, uses the given name as the absolute name of the metric. If false, prepends the package name and class name before the given name. Default value is false.

String displayName

Optional. A human readable display name for metadata.

String description

Optional. A description of the metric.

String unit

Unit of the metric. For @Gauge no default is provided. Check the MetricUnits class for a set of pre-defined units.

boolean reusable

Denotes if a metric with a certain MetricID can be registered in more than one place. Does not apply to gauges.

Note
Implementors are encouraged to issue warnings in the server log if metadata is missing. Implementors MAY stop the deployment of an application if Metadata is missing.

Annotated Naming Convention

Annotated metrics are registered into the application MetricRegistry with the name based on the annotation’s name and absolute fields.

Example of annotated metric names
package com.example;

import javax.inject.Inject;
import org.eclipse.microprofile.metrics.Counter;
import org.eclipse.microprofile.metrics.annotation.Metric;

public class Colours {

  @Inject
  @Metric
  Counter redCount;

  @Inject
  @Metric(name="blue")
  Counter blueCount;

  @Inject
  @Metric(absolute=true)
  Counter greenCount;

  @Inject
  @Metric(name="purple", absolute=true)
  Counter purpleCount;
}

The above bean would produce the following entries in the MetricRegistry

com.example.Colours.redCount
com.example.Colours.blue
greenCount
purple

@Counted

An annotation for marking a method, constructor, or type as a counter.

The implementation must support the following annotation targets:

  • CONSTRUCTOR

  • METHOD

  • TYPE

Note
This annotation has changed in MicroProfile Metrics 2.0: Counters now always increase monotonically upon invocation. The old behaviour pre 2.0 can now be achieved with @ConcurrentGauge.

If the metric no longer exists in the MetricRegistry when the annotated element is invoked then an IllegalStateException will be thrown.

The following lists the behavior for each annotation target.

CONSTRUCTOR

When a constructor is annotated, the implementation must register a counter for the constructor using the Annotated Naming Convention. The counter is increased by one when the constructor is invoked.

Example of an annotated constructor
@Counted
public CounterBean() {
}
METHOD

When a method is annotated, the implementation must register a counter for the method using the Annotated Naming Convention. The counter is increased by one when the method is invoked.

Example of an annotated method
@Counted
public void run() {
}
TYPE

When a type/class is annotated, the implementation must register a counter for each of the constructors and methods using the Annotated Naming Convention. The counters are increased by one when the corresponding constructor/method is invoked.

Example of an annotated type/class
@Counted
public class CounterBean {

  public void countMethod1() {}
  public void countMethod2() {}

}

@ConcurrentGauge

An annotation for marking a method, constructor, or type as a parallel invocation counted. The semantics is such that upon entering a marked item, the parallel count is increased by one and upon exit again decreased by one. The purpose of this annotation is to gauge the number of parallel invocations of the marked methods or constructors.

The implementation must support the following annotation targets:

  • CONSTRUCTOR

  • METHOD

  • TYPE

If the metric no longer exists in the MetricRegistry when the annotated element is invoked then an IllegalStateException will be thrown.

The following lists the behavior for each annotation target.

CONSTRUCTOR

When a constructor is annotated, the implementation must register gauges, representing the current, previous minute maximum, and previous minute minimum values for the constructor using the Annotated Naming Convention.

Example of an annotated constructor
@ConcurrentGauge
public CounterBean() {
}
METHOD

When a method is annotated, the implementation must register gauges, representing the current, previous minute maximum, and previous minute minimum values for the method using the Annotated Naming Convention.

Example of an annotated method
@ConcurrentGauge
public void run() {
}
TYPE

When a type/class is annotated, the implementation must register gauges, representing the current, previous minute maximum, and previous minute minimum values for each of the constructors and methods using the Annotated Naming Convention.

Example of an annotated type/class
@ConcurrentGauge
public class CounterBean {

  public void countMethod1() {}
  public void countMethod2() {}

}

@Gauge

An annotation for marking a method as a gauge. No default MetricUnit is supplied, so the unit must always be specified explicitly.

The implementation must support the following annotation target:

  • METHOD

The following lists the behavior for each annotation target.

METHOD

When a method is annotated, the implementation must register a gauge for the method using the Annotated Naming Convention. The gauge value and type is equal to the annotated method return value and type.

Example of an annotated method
@Gauge(unit = MetricUnits.NONE)
public long getValue() {
  return value;
}

@Metered

An annotation for marking a constructor or method as metered. The meter counts the invocations of the constructor or method and tracks how frequently they are called.

The implementation must support the following annotation targets:

  • CONSTRUCTOR

  • METHOD

  • TYPE

If the metric no longer exists in the MetricRegistry when the annotated element is invoked then an IllegalStateException will be thrown.

The following lists the behavior for each annotation target.

CONSTRUCTOR

When a constructor is annotated, the implementation must register a meter for the constructor using the Annotated Naming Convention. The meter is marked each time the constructor is invoked.

Example of an annotated constructor
@Metered
public MeteredBean() {
}
METHOD

When a method is annotated, the implementation must register a meter for the method using the Annotated Naming Convention. The meter is marked each time the method is invoked.

Example of an annotated method
@Metered
public void run() {
}
TYPE

When a type/class is annotated, the implementation must register a meter for each of the constructors and methods using the Annotated Naming Convention. The meters are marked each time the corresponding constructor/method is invoked.

Example of an annotated type/class
@Metered
public class MeteredBean {

  public void meteredMethod1() {}
  public void meteredMethod2() {}

}

@Timed

An annotation for marking a constructor or method of an annotated object as timed. The metric of type Timer tracks how frequently the annotated object is invoked, and tracks how long it took the invocations to complete.

The implementation must support the following annotation targets:

  • CONSTRUCTOR

  • METHOD

  • TYPE

If the metric no longer exists in the MetricRegistry when the annotated element is invoked then an IllegalStateException will be thrown.

The following lists the behavior for each annotation target.

CONSTRUCTOR

When a constructor is annotated, the implementation must register a timer for the constructor using the Annotated Naming Convention. Each time the constructor is invoked, the execution will be timed.

Example of an annotated constructor
@Timed
public TimedBean() {
}
METHOD

When a method is annotated, the implementation must register a timer for the method using the Annotated Naming Convention. Each time the method is invoked, the execution will be timed.

Example of an annotated method
@Timed
public void run() {
}
TYPE

When a type/class is annotated, the implementation must register a timer for each of the constructors and methods using the Annotated Naming Convention. Each time a constructor/method is invoked, the execution will be timed with the corresponding timer.

Example of an annotated type/class
@Timed
public class TimedBean {

  public void timedMethod1() {}
  public void timedMethod2() {}

}

@Metric

An annotation requesting that a metric should be injected or registered.

The implementation must support the following annotation targets:

  • FIELD

  • METHOD

  • PARAMETER

The following lists the behavior for each annotation target.

FIELD

When a metric producer field is annotated, the implementation must register the metric to the application MetricRegistry (using the Annotated Naming Convention). If a metric with the given name already exist (created by another @Produces for example), an java.lang.IllegalArgumentException must be thrown.

Example of a producer field
@Produces
@Metric(name="hitPercentage")
@ApplicationScoped
Gauge<Double> hitPercentage = new Gauge<Double>() {

  @Override
  public Double getValue() {
      return hits / total;
  }
};

When a metric injected field is annotated, the implementation must provide the registered metric with the given name (using the Annotated Naming Convention) if the metric already exist. If no metric exists with the given name then the implementation must produce and register the requested metric. @Metric can only be used on injected fields of type Meter, Timer, Counter, and Histogram.

Example of an injected field
@Inject
@Metric(name = "applicationCount")
Counter count;
METHOD

When a metric producer method is annotated, the implementation must register the metric produced by the method using the Annotated Naming Convention.

Example of a producer method
@Produces
@Metric(name = "hitPercentage")
@ApplicationScoped
protected Gauge<Double> createHitPercentage() {
    return new Gauge<Double>() {

      @Override
      public Double getValue() {
          return hits / total;
      }
    };
}
PARAMETER

When a metric parameter is annotated, the implementation must provide the registered metric with the given name (using the Annotated Naming Convention) if the metric already exist. If no metric exists with the given name then the implementation must produce and register the requested metric.

Example of an annotated parameter
@Inject
public void init(@Metric(name="instances") Counter instances) {
    instances.inc();
}

Metric Registries

The MetricRegistry is used to maintain a collection of metrics along with their metadata. There is one shared singleton of the MetricRegistry per scope (application, base, and vendor). When metrics are registered using annotations, the metrics are registered in the application MetricRegistry (and thus the application scope).

When injected, the @RegistryType is used as a qualifier to selectively inject either the APPLICATION, BASE, or VENDOR registry. If no qualifier is used, the default MetricRegistry returned is the APPLICATION registry.

Implementations may choose to use a Factory class to produce the injectable MetricRegistry bean via CDI. See [metric-registry-factory]. Note: The factory would be an internal class and not exposed to the application.

@RegistryType

The @RegistryType can be used to retrieve the MetricRegistry for a specific scope. The implementation must produce the corresponding MetricRegistry specified by the RegistryType.

Note
The implementor can optionally provide a read_only copy of the MetricRegistry for base and vendor scopes.

Application Metric Registry

The implementation must produce the application MetricRegistry when no RegistryType is provided (@Default) or when the RegistryType is APPLICATION.

Example of the application injecting the application registry
@Inject
MetricRegistry metricRegistry;
is equivalent to
@Inject
@RegistryType(type=MetricRegistry.Type.APPLICATION)
MetricRegistry metricRegistry;

Base Metric Registry

The implementation must produce the base MetricRegistry when the RegistryType is BASE. The base MetricRegistry must contain the required metrics specified in [required-metrics].

Example of the application injecting the base registry
@Inject
@RegistryType(type=MetricRegistry.Type.BASE)
MetricRegistry baseRegistry;

Vendor Metric Registry

The implementation must produce the vendor MetricRegistry when the RegistryType is VENDOR. The vendor MetricRegistry must contain any vendor specific metrics.

Example of the application injecting the vendor registry
@Inject
@RegistryType(type=MetricRegistry.Type.VENDOR)
MetricRegistry vendorRegistry;

Metadata

Metadata is used in MicroProfile-Metrics to provide immutable information about a Metric at registration time. Metadata in the architecture section describes this further.

Therefore Metadata is an interface to construct an immutable metadata object. The object can be built via a MetadataBuilder with a fluent api.

Example of constucting a Metadata object for a Meter and registering it in Application scope
Metadata m = Metadata.builder()
    .withName("myMeter")
    .withDescription("Example meter")
    .withType(MetricType.METER)
    .addTag("colour=blue")
    .build();

Meter me = new MyMeterImpl();
metricRegistry.register(m, me);

A default implementation DefaultMetadata is provided in the API for convenience.

You can’t perform that action at this time.