Skip to content

Registry

The Registry is the main class for managing a set of meters. A Meter is a class for collecting a set of measurements about your application.

Choose Implementation

The core Spectator library, spectator-api, comes with the following Registry implementations:

Class Dependency Description
DefaultRegistry spectator-api Updates local counters, frequently used with unit tests.
NoopRegistry spectator-api Does nothing, tries to make operations as cheap as possible.

This implementation is typically used to help understand the overhead being created due to instrumentation. It can also be useful in testing to help ensure that no side effects were introduced where the instrumentation is now needed in order for the application for function properly.
MetricsRegistry spectator-reg-metrics3 Map to metrics3 library.

This implementation is typically used for reporting to local files, JMX, or other backends like Graphite. Note that it uses a hierarchical naming scheme rather than the dimensional naming used by Spectator, so the names will get flattened when mapped to this Registry.

It is recommended for libraries to write code against the Registry interface and allow the implementation to get injected by the user of the library. The simplest way is to accept the Registry via the constructor, for example:

public class HttpServer {
  public HttpServer(Registry registry) {
    // use registry to collect measurements
  }
}

The user of the class can then provide the implementation:

Registry registry = new DefaultRegistry();
HttpServer server = new HttpServer(registry);

More complete examples can be found on the testing page or in the spectator-examples repo.

Working with Ids

Spectator is primarily intended for collecting data for dimensional time series backends like Atlas. The ids used for looking up a Meter in the Registry consist of a name and set of tags. Ids will be consumed many times by users after the data has been reported, so they should be chosen with some care and thought about how they will get used. See the conventions page for some general guidelines.

Ids are created via the Registry, for example:

Id id = registry.createId("server.requestCount");

The ids are immutable, so they can be freely passed around and used in a concurrent context. Tags can be added when an id is created:

Id id = registry.createId(
    "server.requestCount",
    "status", "2xx",
    "method", "GET"
);

Or by using withTag and withTags on an existing id:

public class HttpServer {
  private final Id baseId;

  public HttpServer(Registry registry) {
    baseId = registry.createId("server.requestCount");
  }

  private void handleRequestComplete(HttpRequest req, HttpResponse res) {
    // Remember Id is immutable, withTags will return a copy with the
    // the additional metadata
    Id reqId = baseId.withTags(
      "status", res.getStatus(),
      "method", req.getMethod().name());
    registry.counter(reqId).increment();
  }

  private void handleRequestError(HttpRequest req, Throwable t) {
    // Can also be added individually using `withTag`. However, it is better
    // for performance to batch modifications using `withTags`.
    Id reqId = baseId
      .withTag("error",  t.getClass().getSimpleName())
      .withTag("method", req.getMethod().name());
    registry.counter(reqId).increment();
  }
}

Collecting Measurements

Once you have an id, the Registry can be used to get an instance of a Meter to record a measurement. Meters can roughly be categorized in two groups:

Active

Active Meters are ones that are called directly when some event occurs. There are three basic types supported:

  • Counters measure how often something is occurring. This will be reported to backend systems as a rate-per-second. For example, the number of requests processed by a web server.
  • Timers measure how long something took. For example, the latency of requests processed by a web server.
  • Distribution Summaries measure the size of something. For example, the entity sizes for requests processed by a web server.

Passive

Passive Meters are ones where the Registry has a reference to get the value when needed. For example, the number of current connections on a web server or the number threads that are currently in use. These will be Gauges.

Global Registry

There are some use-cases where injecting the Registry is not possible or is too cumbersome. The main example from the core Spectator libraries is the log4j appender. The Global Registry is useful there because logging is often initialized before any other systems and Spectator itself uses logging via the slf4j api which is quite likely being bound to log4j when that the appender is being used. By using the Global Registry, the logging initialization can proceed before the Spectator initialization in the application. Though any measurements taken before a Registry instance has been added will be lost.

The Global Registry is accessed using:

Registry registry = Spectator.globalRegistry();

By default, it will not record anything. For a specific registry instance you can choose to configure it to work with the Global Registry by calling add:

public void init() {
  Registry registry = // Choose an appropriate implementation

  // Add it to the global registry so it will receive
  // any activity on the global registry
  Spectator.globalRegistry().add(registry);
}

Any measurements taken while no Registries are added to the global instance will be lost. If multiple Registries are added, all will receive updates made to the Global Registry.