The Environment in the Probes Open API

How Satoris shares/records data and configure extension points.

The Environment interface in the Probes Open API has a number of uses within the Satoris implementation of the underlying metering engine.

  • Thread Context Values
  • Global Environment Variables
  • Extension Point Configuration
  • Recorded Event Data

Thread Context Values

The Environment interface, accessible via the thread specific Context interface, allows for reading and writing of immutable data values such as String, long, int, boolean, double, and Name.

Note: The data type for named values is limited to allow memory offloading.

Values are local to the current thread and so can be accessed and updated from different call stack frames and across requests on the same thread.

Note: By default, there is no scoping of values to a particular probe call frame.

The Environment acts much like a Map with entries keyed on a Name. But unlike a Map, the Environment is hierarchical namespace aware offering a way to query the presence of values as well as removal using a Name prefix.

In the code snippet above user is the Name prefix of

Here’s the console output of the code executed within a metered runtime.

The Environment interface can also be used to access read-only metadata associated with the current thread. This information is similar to what is offered by the Thread class. This might appear redundant, until factoring in the interesting novel capabilities offered by add-ons such as Stenos and Simz allowing the exact same code to be executed within a lightweight simulated environment replaying episodic memories of one or more Java runtimes.

The Environment interface allows extension point code, such as interceptors or strategies, to be independent of the execution process — real or simulated.

In the Satoris implementation there exist multiple Environment instances chained together with only the leaf instance accessible via the Context.

The Environment returned from the Context.getEnvironment method is mutable. So named values can be added, updated and removed locally. But when querying a value mapped to a Name resolution starts with the target instance and when not found is delegated upwards to a parent instance.

The Thread metadata, created by the metering engine, cannot be removed or changed. The values are read-only, though it is possible to hide a value using the mutable Environment and setting a new value including null.

The Environment interface is also used to pass data back-and-forth between the application and metering extensions enabled within the runtime.

An example of this would be the current metering extension in Satoris which allows an application to determine the name of the active probe.

The qos metering extension in Sentris, which builds on top of the Satoris foundation, allows for an application to dynamically override the priority level for the current QoS Service associated with the running thread.

The Environment interface reduces the overall surface area of the Open API in not polluting the Context with many [get|set]${SpecificThing}() methods — especially important when a metering engine has many optional extensions.

Global Environment Variables

Satoris also uses the Environment interface to expose metadata associated with the process. Similar to extensions the Environment data is read-only.

read access delegation

To the application the global metadata variables appear to be contained within the local Environment accessible from the thread Context. In fact any Environment used in the Open API delegates to this global instance.

Again using the Environment to access process information ensures that the code can be run within both a real or simulated software machine process.

Note: In Simz there’s no one process Environment instance as a runtime can be simultaneously playing back episodic memories for multiple metered processes.

Satoris allows for the setting of global variables beyond what the metering engine already captures and sets. Here is a configuration file specifying some global variables. The last two variables are mapped to existing system variables — a Java system property and a system-dependent named variable.

Note: The Satoris configuration allows for the type specification of variables.

Note: The same property spec pattern is used in configuring extension points.

And the code to access the above custom global variables from any thread.

Extension Point Configuration

The Environment interface is also used to pass configuration to extension points in Satoris. Below an interceptor is passed the name of it’s meter.

The InterfaceFactory class is passed an Environment via the init method.

The measure and strategy extension points offer the same init method.

Note: Global environment variables are also resolvable from the Environment. This is useful where multiple extension points share a common configuration.

Recorded Event Data

Both the stenos and simz metering extensions intercept Environment calls and write the set data values within their respective metering event streams along with other metering events and metadata. When the ultra-compressed binary event stream is played back at some later point inside a simulation the values are made present at probe call boundaries — begin() and end().

One way to see it is that before the instrumented move() call is made the X and Y parameters are pushed on/into the corresponding probe stack frame.

To see the above code in action check out the following walkthrough video.

Collective Intelligence - Distributed Replication & Simulated Playback

A visual demonstration of how to augment the collective execution behavior of multiple software applications within a single simulated process. April 2014

Additional API Design Notes


The Environment interface doesn’t allow for the iteration over named values. The thinking being that values should only be accessible, to both application and extensions, on a need to know basis. If the name is not known, made public docs, then the value can’t be retrieved. Not offering iteration allows for performance optimizations and reduces design and development work when employing chained name resolution and memory management.


A common use case for Environment is to override defaults. To make such coding easier there’s a get${Type}(Name,${Type}) method for each type.


While the Environment is accessible via the thread Context it does not altogether preclude the underlying metering engine implementation from creating frames, scopes, restricting the lifecycle of the values to that of the active probe metering window — between the begin() and end() calls. This is in contrast to the OpenTracing API which practically forces implementors to incur large and unnecessary temporary heap object allocations per trace.

Values can still be scoped by the application itself using a try-finally code block though this would not be applicable to re-entrant methods.

Satoris 2.8 will offer an optional metering extension that automatically stacks.


The Environment interface makes a distinction between not present and null. The contains(Name) method reports on the existence of a Name within the map whereas isNull(Name) on the value of the named value. This is required when values, passed as parameters, can be primitive types.


Other than Name and String all data values are primitive types. More complex data structures can be supported by setting multiple values with a common namespace.

William Louth. Software engineer specialized in self-adaptive software runtimes, adaptive control, self-regulation, resilience engineering & visualization.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store