The Toolkit #2

Leveling Up

The Substrates project provides a cohesive and coherent set of concepts and contracts that we have found as repeating structural and behavioral patterns across our past, present, and future instrumentation and measurement software library designs.

We covered three important primary concepts with the Substrates library in the last post: Name, Environment, and Variable. In this follow-up post, we discuss the conceptualization of the Context and Instrument interfaces and secondary supporting interfaces such as Source, Container, and Substrate.

The Context Interface

The Context interface is an amalgamation of three interfaces – Source, Container, and Environmental. The primary purpose of the Context is to manage the lifecycle of Instrument instances created with and mapped to Name instances. A Context holds a single type of Instrument. Each Humainary instrument project built on the Substrates library adheres to this restriction in introducing its extension to the Context interface. The Substrates project does not provide a way to create a Context; it merely defines the contract.

The Source interface is an abstraction of an observable event source, exposing methods to subscribe to the notification of changes via the registration of a Subscriber and, in turn, Sink, both of which will be discussed at length within a future posting. When an Instrument measures an event or change, the Context managing its lifecycle will publish an emittance; a Context is an event hub.

The Container interface is an abstraction of the mapping from a Name to a value; in the case of Context, the value type is an Instrument. With a Container, one can look up a named value and iterate over a set of named values.

The Substrate interface has a single method that returns an Environment. With the returned Environment, it is possible to introspect the underlying configuration and runtime state not exposed elsewhere. Both the Context and Instrument interfaces extend the Substrate interface.

A service provider interface (SPI) implementation of an instrument library should use this mechanism to publish diagnostic data.

The Instrument Interface

The Instrument is a marker-like interface for instruments that combines Named and Environmental interfaces. The Substrate interface we have already discussed above regarding the Context interface, though it might be useful also to mention that placing this interface here in the hierarchy enables a generic introspection of Instrument instances across different Instrument types. This is particularly important for plugins and extensions discussed later in this series of articles on the toolkit.

The Named interface defines a single method that returns the Name mapped to the Instrument.

The Instrument is the (re)active component that publishes measurements and events via the owning Context. Every transmission of a Source emittance to a Subscriber and Sink includes the Name of the Instrument and the manifest.

Example Code Listing

package io.humainary.counters.samples;

import io.humainary.counters.Counters;
import io.humainary.substrates.Substrates.Name;

import static;
import static java.lang.System.out;

public class Level2 {

  static final Name ENTER =
    name ( "enter" );

  static final Name EXIT =
    name ( "exit" );

  public static void main (
    final String[] args
  ) {

    // creates a non-shared counters context

    final var context =
      Counters.context ();

    // every context exposes an environment

      context.getEnvironment () != null;

    final var enter =
      context.counter (

      enter.getName () == ENTER; ();

    final var exit =
      context.counter (

      exit.getName () == EXIT; ();

    for ( final var counter : context ) {

      // every instrument exposes an environment

        counter.getEnvironment () != null;

      out.println (
        counter.getName ()