Observability - Ruby SDK
This page covers capabilities related to viewing the state of the application, including:
The observability guide covers the many ways to view the current state of your Temporal Application. This includes viewing Workflow Executions tracked by the Temporal Platform, as well as inspecting state at any point during execution.
Emit metrics
Each Temporal SDK can optionally emit metrics from either the Client or Worker process.
- Metrics can be scraped by systems like Prometheus.
- Graphs can be created using tools like Grafana.
- For a list of metrics, see the SDK metrics reference.
Metrics in Ruby are configured on the metrics
argument of the telemetry
argument when creating a global Temporalio::Runtime
. That object should be created globally and should be used for all clients; therefore, you should configure this before any other Temporal code.
Set a Prometheus endpoint
The following example exposes a Prometheus endpoint on port 9000
.
Temporalio::Runtime.default = Temporalio::Runtime.new(
telemetry: Temporalio::Runtime::TelemetryOptions.new(
metrics: Temporalio::Runtime::MetricsOptions.new(
prometheus: Temporalio::Runtime::PrometheusMetricsOptions.new(
bind_address: '0.0.0.0:9000'
)
)
)
)
Custom metric handling
Instead of Prometheus or OpenTelemetry, an instance of Temporalio::Runtime::MetricBuffer
can be provided as a buffer
argument to the MetricsOptions
.
retrieve_updates
can then be periodically called on the buffer to get metric updates.
Setup Tracing
Tracing enables observability into the sequence of calls across your application, including Workflows and Activities.
OpenTelemetry tracing for clients, activities, and workflows can be enabled using the Temporalio::Contrib::OpenTelemetry::TracingInterceptor
. Specifically, when creating a client, set the interceptor like so:
require 'opentelemetry/api'
require 'opentelemetry/sdk'
require 'temporalio/client'
require 'temporalio/contrib/open_telemetry'
# ... assumes my_otel_tracer_provider is a tracer provider created by the user
my_tracer = my_otel_tracer_provider.tracer('my-otel-tracer')
my_client = Temporalio::Client.connect(
'localhost:7233', 'my-namespace',
interceptors: [Temporalio::Contrib::OpenTelemetry::TracingInterceptor.new(my_tracer)]
)
When your Client is connected, spans are created for all Client calls, Activities, and Workflow invocations on the Worker. Spans are created and serialized through the server to give one trace for a Workflow Execution.
Log from a Workflow
Logging enables you to capture and persist important execution details from your Workflow and Activity code.
Logging levels typically include:
Level | Use |
---|---|
DEBUG | Detailed information, typically useful for debugging purposes. |
INFO | General information about the application's operation. |
WARN | Indicates potentially harmful situations or minor issues that don't prevent the application from working. |
ERROR | Indicates error conditions that might still allow the application to continue running. |
Logging uses the Ruby standard logging APIs.
The logger
can be set when connecting a client.
The following example shows logging on the console and sets the level to INFO
.
require 'logger'
require 'temporalio/client'
my_client = Temporalio::Client.connect(
'localhost:7233', 'my-namespace',
logger: Logger.new($stdout, level: Logger::INFO)
)
You can log from a Workflow using Temporalio::Workflow.logger
which is a special instance of Ruby's Logger
that
appends workflow details to every log and does not log during replay.
Temporalio::Workflow.logger.info("Some log #{some_value}")
There's also one for use in activities that appends Activity details to every log:
Temporalio::Activity::Context.current.logger.info("Some log #{some_value}")
Use Visibility APIs
Visibility refers to Temporal features for listing, filtering, and inspecting Workflow Executions.
Use Search Attributes
- Default Search Attributes like
WorkflowType
,StartTime
, andExecutionStatus
are automatically indexed. - Custom Search Attributes let you store domain-specific metadata for Workflows.
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 Attributes.
- Default Search Attributes like
WorkflowType
,StartTime
andExecutionStatus
are automatically added to Workflow Executions. - Custom Search Attributes can contain their own domain-specific data (like
customerId
ornumItems
). - A few generic Custom Search Attributes like
CustomKeywordField
andCustomIntField
are created by default in Temporal's Docker Compose.
The steps to using custom Search Attributes are:
- Create a new Search Attribute in your Temporal Service in the CLI or Web UI.
- For example:
temporal operator search-attribute create --name CustomKeywordField --type Text
- Replace
CustomKeywordField
with the name of your Search Attribute. - Replace
Text
with a type value associated with your Search Attribute:Text
|Keyword
|Int
|Double
|Bool
|Datetime
|KeywordList
- Replace
- For example:
- Set the value of the Search Attribute for a Workflow Execution:
- On the Client by including it as an argument when starting the Execution.
- In the Workflow by calling
Temporalio::Workflow.upsert_search_attributes
.
- Read the value of the Search Attribute:
- On the Client by calling
describe
on aWorkflowHandle
. - In the Workflow by looking at
Temporalio::Workflow.search_attributes
.
- On the Client by calling
- Query Workflow Executions by the Search Attribute using a List Filter:
- In the Temporal CLI
- In code by calling
list_workflows
.
List Workflow Executions
Use the list_workflows method on the Client and pass a List Filter as an argument to filter the listed Workflows. The result is a lazy enumerator/enumerable.
my_client.list_workflows("WorkflowType='GreetingWorkflow'").each do |wf|
puts "Workflow: #{wf.id}"
end
Set Custom Search Attributes
After you've created custom Search Attributes in your Temporal Service (using temporal operator search-attribute create
or the Cloud UI), you can set the values of the custom Search Attributes when starting a Workflow.
To set custom Search Attributes, use the search_attributes
parameter for start_workflow
or execute_workflow
.
Keys should be predefined for reuse.
# Predefined search attribute key, usually a global somewhere
MY_KEYWORD_KEY = Temporalio::SearchAttributes::Key.new(
'my-keyword',
Temporalio::SearchAttributes::IndexedValueType::KEYWORD
)
# ...
# Start workflow with the search attribute set
handle = my_client.start_workflow(
MyWorkflow, 'some-input',
id: 'my-workflow-id', task_queue: 'my-task-queue',
search_attributes: Temporalio::SearchAttributes.new({ MY_KEYWORD_KEY => 'some-value' })
)
Upsert Search Attributes
You can upsert Search Attributes to add, update, or remove Search Attributes from within Workflow code.
To upsert custom Search Attributes, use the upsert_search_attributes
method with a set of updates.
Keys should be predefined for reuse.
# Predefined search attribute key, usually a global somewhere
MY_KEYWORD_KEY = Temporalio::SearchAttributes::Key.new(
'my-keyword',
Temporalio::SearchAttributes::IndexedValueType::KEYWORD
)
# ...
class MyWorkflow < Temporalio::Workflow::Definition
def execute
# ...
Temporalio::Workflow.upsert_search_attributes(MY_KEYWORD_KEY.value_set('some-new-value'))
# ...
end
end