The Substrates project is the reference implementation for the Humainary Substrates service provider interface (SPI). The project defines various foundational interfaces employed across all observability software libraries.


The Substrates toolkit comprises four packaged component types – API, SPI, Provider, and SDK. The first component is the API, the main entry point class that defines only client calling interfaces. The second component is the SPI, which defines the interface contract between the API and a Provider implementation. The third component is the Provider, which provides the implementation of API and SPI interfaces. The fourth component is the SDK, which includes base implementations of API interface for use across Providers.



The Substrates class is the main entry point into the toolkit. It is the only class in the API component. All API interfaces are defined as inner interfaces within Substrates. The Substrates class is responsible for the bootstrapping of a Provider. It offers class-level methods that create interface instances by delegating to the Provider.


The Substrate is an interface implemented by all object types produced by a Provider. It exposes configuration and runtime state via an Environment object obtained by the environment method. The Environment is the preferred means by which a Provider can expose extensions to a standard interface.


The Extent interface is an abstraction of a nested structure, where an Extent is enclosed within another. Within the toolkit, the Name interface extends the Extent interface. The Extent interface offers various functional styled traversal methods such as foldTo and foldFrom. The enclosure method of the interface returns the enclosing Extent. The extremity method returns the outermost enclosing Extent.


The Name interface is used to look up an Instrument within a Context or a state value via an Environment. A Name is a sequence of String parts, like a domain name or namespace. Using a Name instead of a String, a Provider can employ performance and memory optimizations. The Name interface extends both the Substrate and Extent interfaces.


The Lookup interface defines two get methods used to retrieve an object or value using a Name. The first method returns an Optional that wraps a matched value or null. The second method allows the specification of a default return value if no match is found.


The Environment interface is an abstraction for interfacing with configuration stores, including the state of a Substrate. The interface extends the Lookup interface, adding additional value type-specific methods. It is an immutable interface, though multiple Environment instances can be chained and composed. The Environment interface is used to configure the creation of a Context. All Substrate instances offer access to their internal runtime state via an associated Environment instance.


The Variable interface efficiently retrieves a value from an Environment or Substrate. A Variable instance is created with a Name and a default value. The of method in the Variable interface extracts the Name mapped value from a provided Substrate or Environment. The Variable instance itself can be seen as stateless and treated as a constant, whether to cache is a Provider choice.


The Type interface represents the interface type of a Referent. The name method in the interface returns the Name representation of the type’s class. The Type interface extends Substrate, allowing additional metadata to be exposed via the environment method.


The Reference interface identifies and tracks a Referent across spatial and temporal event flow boundaries. Consumers within the Event pipeline have no direct access to the emitting Referent; instead, the Reference is used. A Reference is a Substrate that provides access to an Environment that includes the state values of the Referent. The name method in the interface returns the Name of the Referent.

The type method in the interface returns a Name representation of the interface class name. The Reference interface extends Extent allowing for a Reference to be enclosed within another Reference, such as an Instrument within a Context.


The Referent interface marks a Substrate sub-type as recurrent and referable within a Container. The reference method in the interface returns a Reference that is used as a substitute within event processing.


The Container interface extends both Substrate and Lookup interfaces. It represents a collection of Referents that can be retrieved by Name or Reference. The interface is read-only in that it offers no means to create and add a Referent to the Container. An extension or implementation can lazily construct named mapped Referents as in the case of a Context. The Container interface extends the Iterable interface supporting iteration over contained Referents.


The Source interface enables local code to subscribe to Events published by a collection of Referents. A Source acts as an intermediary network hub between Event emitters, Referents, and consumers, Outlets. The subscribe method in the interface allows for the registration of a Subscriber, returning a Subscription. The Source is responsible for the routing and delivery of Events and the management of Subscriptions.


The Subscriber interface is used to selectively register interest in Events for a Referent mediated by a Source. A Subscriber does not consume Events; instead, it is given the means to register an Outlet for a particular Referent. A Source to which the Subscriber has subscribed will call the accept method in the interface for each emitting Referent. When a Subscriber is registered with a Source, a Subscription is returned that can be used to cancel Event consumption.


The Subscription interface allows for the cancellation of Event dispatching to Outlets registered by a Subscriber. The cancel method in the interface unsubscribes the Subscriber and unregisters its Outlets. The Subscription interface extends AutoCloseable making it automatic resource management enabled.


The Registrar interface is used for registering an Outlet for a Reference for Event consumption. A Registrar is passed as a callback parameter to a Subscriber whenever a new Referent starts emitting Events. A Subscriber within its accept method registers an Outlet for a Referent using the register method.


The Event interface is an envelope structure enclosing an emittance value mediated by a Source and emitted by a Referent. The emitter method in the interface returns a Reference to the emitting Referent. The emittance method returns the value emitted by the Referent via the mediating Source. The Event interface is a Substrate and can expose additional state values via its Environment.


The Outlet interface consumes Events emitted by a Referent and mediated by a Source. An Outlet can be hooked up to a Source via a Subscriber or directly, where it effectively acts as a collect-all sink. The accept method in the Outlet interface receives an Event of the emittance value type defined by the Source.


The Inlet interface emits an emittance value via a Conduit that wraps the publication within an Event envelope. Within the interface, there are two emit-named methods. One takes a typed value, the other a Supplier of a typed value. Within the SDK component, the Inlet interface provides the base Instrument publication capabilities.


The Conduit interface creates and manages Inlets mapped to a Reference. The inlet method in the interface takes a single parameter of type Reference and returns an Inlet. The Conduit interface represents the emittance publication aspect of the Hub interface.


The Hub interface extends both Source and Conduit interfaces. The Hub is typically employed to connect event flow processing across multiple Contexts. Within the SDK component, the Hub provides Source aspects of the Context interface.


The Fiber interface represents a flow of execution (thread) within a Fabric (process). Every Event published includes an executor attribute referencing the Fiber in which the emittance occurred. The Name returned by the Reference interface is the class name of the Thread. Other aspects of the underlying Thread instance should be made accessible via the associated Environment, including the name and id of the Thread instance instead of the id of the Reference.


The Fabric interface represents a fabrication (process) of Fibers (threads). The fiber method returns the Fiber associated with the current thread of execution. The Fabric interface extends the Source interface providing a means to subscribe to all events emitted by a Fiber across all possible Contexts and Inlets.

Note: Events will not be dispatched to registered Outlets at the Fabric level unless the emittance is being dispatched to registered Outlets at the Context level.


The Context interface is a composition of both Source and Container interfaces. It is a Source that mediates the emittance of Events from Instruments to Outlets. As a Container, the Context allows the lookup of an Instrument via a Name. A Context manages a single type of Instrument and emits a single emittance value type. The Substrates toolkit does not provide a way to create a Context; it merely defines the contract. All Instrument libraries redefine a Context that extends Context defined in the Substrates library. Each extension of the Context interface in Instrument libraries provides one or more methods to create an Instrument.


The Instrument interface is a marker for observability instruments that measure and emit some phenomenon as an Event. All instrumentation-specific interfaces defined in libraries must extend from this interface.