Skip to main content

Java SDK developer's guide - Observability

The observability section of the Temporal Developer's guide covers the many ways to view the current state of your Temporal ApplicationLink preview iconWhat is a Temporal Application

A Temporal Application is a set of Workflow Executions.

Learn more—that is, ways to view which Workflow Executions are tracked by the Temporal PlatformLink preview iconWhat is the Temporal Platform?

The Temporal Platform consists of a Temporal Cluster and Worker Processes.

Learn more and the state of any specified Workflow Execution, either currently or at points of an execution.

WORK IN PROGRESS

This guide is a work in progress. Some sections may be incomplete or missing for some languages. Information may change at any time.

If you can't find what you are looking for in the Developer's guide, it could be in older docs for SDKs.

This section covers features related to viewing the state of the application, including:

Metrics

Each Temporal SDK is capable of emitting an optional set of metrics from either the Client or the Worker process. For a complete list of metrics capable of being emitted, see the SDK metrics referenceLink preview iconSDK metrics

The Temporal SDKs emit metrics from Temporal Client usage and Worker Processes.

Learn more.

Metrics can be scraped and stored in time series databases, such as:

Temporal also provides a dashboard you can integrate with graphing services like Grafana. For more information, see:

To emit metrics with the Java SDK, use theMicrometerClientStatsReporter class to integrate with Micrometer MeterRegistry configured for your metrics backend. Micrometer is a popular Java framework that provides integration with Prometheus and other backends.

The following example shows how to use MicrometerClientStatsReporter to define the metrics scope and set it with the WorkflowServiceStubsOptions.

//...
// see the Micrometer documentation for configuration details on other supported monitoring systems.
// in this example shows how to set up Prometheus registry and stats reported.
PrometheusMeterRegistry registry = new PrometheusMeterRegistry(PrometheusConfig.DEFAULT);
StatsReporter reporter = new MicrometerClientStatsReporter(registry);
// set up a new scope, report every 10 seconds
Scope scope = new RootScopeBuilder()
.reporter(reporter)
.reportEvery(com.uber.m3.util.Duration.ofSeconds(10));
// for Prometheus collection, expose a scrape endpoint.
//...
// add metrics scope to WorkflowServiceStub options
WorkflowServiceStubsOptions stubOptions =
WorkflowServiceStubsOptions.newBuilder().setMetricsScope(scope).build();
//...

For more details, see the Java SDK Samples. For details on configuring a Prometheus scrape endpoint with Micrometer, see the Micrometer Prometheus Configuring documentation.

Tracing

Tracing allows you to view the call graph of a Workflow along with its Activities and any Child Workflows.

Temporal Web's tracing capabilities mainly track Activity Execution within a Temporal context. If you need custom tracing specific for your use case, you should make use of context propagation to add tracing logic accordingly.

For information about Workflow tracing, see Tracing Temporal Workflows with DataDog.

For information about how to configure exporters and instrument your code, see Tracing Temporal Services with OTEL.

To configure tracing in Java, register the OpenTracingClientInterceptor() interceptor. You can register the interceptors on both the Temporal Client side and the Worker side.

The following code examples demonstrate the OpenTracingClientInterceptor() on the Temporal Client.

WorkflowClientOptions.newBuilder()
//...
.setInterceptors(new OpenTracingClientInterceptor())
.build();
WorkflowClientOptions clientOptions =
WorkflowClientOptions.newBuilder()
.setInterceptors(new OpenTracingClientInterceptor(JaegerUtils.getJaegerOptions(type)))
.build();
WorkflowClient client = WorkflowClient.newInstance(service, clientOptions);

The following code examples demonstrate the OpenTracingClientInterceptor() on the Worker.

WorkerFactoryOptions.newBuilder()
//...
.setWorkerInterceptors(new OpenTracingWorkerInterceptor())
.build();
WorkerFactoryOptions factoryOptions =
WorkerFactoryOptions.newBuilder()
.setWorkerInterceptors(
new OpenTracingWorkerInterceptor(JaegerUtils.getJaegerOptions(type)))
.build();
WorkerFactory factory = WorkerFactory.newInstance(client, factoryOptions);

For more information, see the Temporal OpenTracing module.

Logging

Send logs and errors to a logging service, so that when things go wrong, you can see what happened.

The SDK core uses WARN for its default logging level.

To get a standard slf4j logger in your Workflow code, use the Workflow.getLogger method.

private static final Logger logger = Workflow.getLogger(DynamicDslWorkflow.class);

Logs in replay mode are omitted unless the WorkerFactoryOptions.Builder.setEnableLoggingInReplay(boolean) method is set to true.

Custom logger

Use a custom logger for logging.

To set a custom logger, supply your own logging implementation and configuration details the same way you would in any other Java application.

Visibility

The term Visibility, within the Temporal Platform, refers to the subsystems and APIs that enable an operator to view Workflow Executions that currently exist within a Cluster.

Search Attributes

The typical method of retrieving a Workflow Execution is by its Workflow Id.

However, sometimes you'll want to retrieve one or more Workflow Executions based on another property. For example, imagine you want to get all Workflow Executions of a certain type that have failed within a time range, so that you can start new ones with the same arguments.

You can do this with Search AttributesLink preview iconWhat is a Search Attribute?

A Search Attribute is an indexed name used in List Filters to filter a list of Workflow Executions that have the Search Attribute in their metadata.

Learn more.

The steps to using custom Search Attributes are:

Here is how to query Workflow Executions:

Custom Search Attributes

After you've created custom Search Attributes in your Cluster (using tctl search-attribute createor the Cloud UI), you can set the values of the custom Search Attributes when starting a Workflow.

To set a custom Search Attribute, call the setSearchAttributes() method.

WorkflowOptions workflowOptions =
WorkflowOptions.newBuilder()
.setSearchAttributes(generateSearchAttributes())
.build();

generateSearchAttributes() is a Map<String, ?> from the Search Attribute used as the key to a value of one of the following types.

  • String
  • Long
  • Integer
  • Boolean
  • Double
  • OffsetDateTime

Upsert Search Attributes

You can upsert Search Attributes to add or update Search Attributes from within Workflow code.

In your Workflow code, call the upsertSearchAttributes(Map<String, ?> searchAttributes) method.

 Map<String, Object> attr1 = new HashMap<>();
attr1.put("CustomIntField", 1);
attr1.put("CustomBoolField", true);
Workflow.upsertSearchAttributes(attr1);

Map<String, Object> attr2 = new HashMap<>();
attr2.put("CustomIntField", Lists.newArrayList(1, 2));
attr2.put("CustomKeywordField", "Seattle");
Workflow.upsertSearchAttributes(attr2);

The results of upsertSearchAttributes() output the following search attributes.

{
"CustomIntField": 1, 2,
"CustomBoolField": true,
"CustomKeywordField": "Seattle",
}

Remove Search Attribute

To remove a Search Attribute that was previously set, set it to an empty array: [].

To remove a Search Attribute, call the upsertSearchAttributes() method and set it to an empty map.