Skip to content

Commit

Permalink
Fix #100: Enable Micrometer Metrics (#101)
Browse files Browse the repository at this point in the history
  • Loading branch information
melloware authored Sep 4, 2024
1 parent 9c59c5a commit 2ac2483
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 12 deletions.
35 changes: 35 additions & 0 deletions docs/modules/ROOT/pages/includes/quarkus-temporal.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,41 @@ endif::add-copy-button-to-env-var[]
|


a| [[quarkus-temporal_quarkus-temporal-metrics-enabled]]`link:#quarkus-temporal_quarkus-temporal-metrics-enabled[quarkus.temporal.metrics.enabled]`


[.description]
--
Enable Micrometer, enabled by default if Micrometer capability is detected.

ifdef::add-copy-button-to-env-var[]
Environment variable: env_var_with_copy_button:+++QUARKUS_TEMPORAL_METRICS_ENABLED+++[]
endif::add-copy-button-to-env-var[]
ifndef::add-copy-button-to-env-var[]
Environment variable: `+++QUARKUS_TEMPORAL_METRICS_ENABLED+++`
endif::add-copy-button-to-env-var[]
--|boolean
|`true`


a| [[quarkus-temporal_quarkus-temporal-metrics-report-duration]]`link:#quarkus-temporal_quarkus-temporal-metrics-report-duration[quarkus.temporal.metrics.report.duration]`


[.description]
--
The interval at which we report metrics to the metric registry. Default is 15 seconds.

ifdef::add-copy-button-to-env-var[]
Environment variable: env_var_with_copy_button:+++QUARKUS_TEMPORAL_METRICS_REPORT_DURATION+++[]
endif::add-copy-button-to-env-var[]
ifndef::add-copy-button-to-env-var[]
Environment variable: `+++QUARKUS_TEMPORAL_METRICS_REPORT_DURATION+++`
endif::add-copy-button-to-env-var[]
--|link:https://docs.oracle.com/javase/8/docs/api/java/time/Duration.html[Duration]
link:#duration-note-anchor-{summaryTableId}[icon:question-circle[title=More information about the Duration format]]
|`15S`


a|icon:lock[title=Fixed at build time] [[quarkus-temporal_quarkus-temporal-worker-build-id]]`link:#quarkus-temporal_quarkus-temporal-worker-build-id[quarkus.temporal.worker.build-id]`

`link:#quarkus-temporal_quarkus-temporal-worker-build-id[quarkus.temporal.worker."worker-name".build-id]`
Expand Down
34 changes: 30 additions & 4 deletions docs/modules/ROOT/pages/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,14 @@ If you don't have control over the workflow class, it is also possible to bind i

[source,properties]
----
quarkus.temporal.worker.namedWorker.workflow-classes[0]: io.quarkiverse.temporal.SendEmailWorkflowImpl
quarkus.temporal.worker.namedWorker.workflow-classes[0]=io.quarkiverse.temporal.SendEmailWorkflowImpl
----

In this case, it will not be associated with the default worker unless you also bind it explicitely:

[source,properties]
----
quarkus.temporal.worker.workflow-classes[0]: io.quarkiverse.temporal.SendEmailWorkflowImpl
quarkus.temporal.worker.workflow-classes[0]=io.quarkiverse.temporal.SendEmailWorkflowImpl
----

Each worker can have at most one implementation of a given workflow, but a workflow can have implementations across multiple workers.
Expand Down Expand Up @@ -144,14 +144,14 @@ If you don't have control over the activity class, it is also possible to bind i

[source,properties]
----
quarkus.temporal.worker.namedWorker.activity-classes[0]: io.quarkiverse.temporal.SendEmailActivitiesImpl
quarkus.temporal.worker.namedWorker.activity-classes[0]=io.quarkiverse.temporal.SendEmailActivitiesImpl
----

In this case, it will not be associated with the default worker unless you also bind it explicitely:

[source,properties]
----
quarkus.temporal.worker.activity-classes[0]: io.quarkiverse.temporal.SendEmailActivitiesImpl
quarkus.temporal.worker.activity-classes[0]=io.quarkiverse.temporal.SendEmailActivitiesImpl
----

Similarly, each worker can have at most one implementation of a given activity, but an activity can have implementations across multiple workers.
Expand Down Expand Up @@ -250,6 +250,32 @@ To wire up Temporal to forward traces and spans to Quarkus OpenTelemetry simply
</dependency>
----

This will enable it by default you can disable it with:

[source,properties]
----
quarkus.temporal.telemetry.enabled=false
----

== Micrometer Metrics

To wire up Temporal to forward Micrometer metrics to Quarkus OpenTelemetry simply add the Micrometer extension to your application.

[source,xml]
----
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-micrometer-registry-prometheus</artifactId>
</dependency>
----

This will enable it by default you can disable it with:

[source,properties]
----
quarkus.temporal.metrics.enabled=false
----

== Context Propagation

You can use an MDC (Mapped Diagnostic Context) Context Propagator to propagate information from the workflow client to workflow execution, workflow to activity, workflow to child workflow, and workflow to child thread created using `Async`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static io.quarkiverse.temporal.Constants.DEFAULT_WORKER_NAME;
import static io.quarkiverse.temporal.Constants.TEMPORAL_TESTING_CAPABILITY;
import static io.quarkus.deployment.Capability.OPENTELEMETRY_TRACER;
import static io.quarkus.runtime.metrics.MetricsFactory.MICROMETER;

import java.util.ArrayList;
import java.util.Arrays;
Expand Down Expand Up @@ -57,6 +58,7 @@
import io.quarkus.deployment.builditem.FeatureBuildItem;
import io.quarkus.deployment.builditem.ServiceStartBuildItem;
import io.quarkus.deployment.builditem.ShutdownContextBuildItem;
import io.quarkus.deployment.metrics.MetricsCapabilityBuildItem;
import io.quarkus.deployment.pkg.builditem.ArtifactResultBuildItem;
import io.quarkus.info.GitInfo;
import io.quarkus.runtime.configuration.ConfigurationException;
Expand Down Expand Up @@ -315,9 +317,12 @@ void produceActivityBeans(
@Record(ExecutionTime.RUNTIME_INIT)
WorkflowClientBuildItem recordWorkflowClient(
WorkflowServiceStubsRecorder recorder,
WorkflowClientRecorder clientRecorder) {
WorkflowClientRecorder clientRecorder,
Optional<MetricsCapabilityBuildItem> metricsCapability) {

WorkflowServiceStubs workflowServiceStubs = recorder.createWorkflowServiceStubs();
boolean micrometerSupported = metricsCapability.isPresent() && metricsCapability.get().metricsSupported(MICROMETER);

WorkflowServiceStubs workflowServiceStubs = recorder.createWorkflowServiceStubs(micrometerSupported);
return new WorkflowClientBuildItem(
clientRecorder.createWorkflowClient(workflowServiceStubs));
}
Expand Down Expand Up @@ -508,4 +513,4 @@ public boolean getAsBoolean() {
}
}

}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
package io.quarkiverse.temporal;

import java.time.Duration;

import com.uber.m3.tally.RootScopeBuilder;
import com.uber.m3.tally.Scope;
import com.uber.m3.tally.StatsReporter;

import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Metrics;
import io.quarkiverse.temporal.config.ConnectionRuntimeConfig;
import io.quarkiverse.temporal.config.RpcRetryRuntimeConfig;
import io.quarkiverse.temporal.config.TemporalRuntimeConfig;
import io.quarkus.runtime.annotations.Recorder;
import io.temporal.common.reporter.MicrometerClientStatsReporter;
import io.temporal.serviceclient.RpcRetryOptions;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.serviceclient.WorkflowServiceStubsOptions;
Expand Down Expand Up @@ -35,19 +44,35 @@ public RpcRetryOptions createRpcRetryOptions(RpcRetryRuntimeConfig rpcRetry) {
return builder.build();
}

public WorkflowServiceStubsOptions createWorkflowServiceStubsOptions(ConnectionRuntimeConfig connection) {
public WorkflowServiceStubsOptions createWorkflowServiceStubsOptions(ConnectionRuntimeConfig connection,
boolean isMicrometerEnabled) {
if (connection == null) {
return WorkflowServiceStubsOptions.getDefaultInstance();
}

Duration reportDuration = runtimeConfig.metricsReportInterval();
Scope scope = null;
if (isMicrometerEnabled && reportDuration.getSeconds() > 0) {
MeterRegistry registry = Metrics.globalRegistry;
StatsReporter reporter = new MicrometerClientStatsReporter(registry);
// set up a new scope, report every N seconds
scope = new RootScopeBuilder()
.reporter(reporter)
.reportEvery(com.uber.m3.util.Duration.ofSeconds(reportDuration.getSeconds()));
}

WorkflowServiceStubsOptions.Builder builder = WorkflowServiceStubsOptions.newBuilder()
.setRpcRetryOptions(createRpcRetryOptions(connection.rpcRetry()))
.setTarget(connection.target())
.setMetricsScope(scope)
.setEnableHttps(connection.enableHttps());
return builder.build();
}

public WorkflowServiceStubs createWorkflowServiceStubs() {
return WorkflowServiceStubs.newServiceStubs(createWorkflowServiceStubsOptions(runtimeConfig.connection()));
public WorkflowServiceStubs createWorkflowServiceStubs(boolean micrometerSupported) {
boolean isMicrometerEnabled = micrometerSupported && runtimeConfig.metricsEnabled();
return WorkflowServiceStubs
.newServiceStubs(createWorkflowServiceStubsOptions(runtimeConfig.connection(), isMicrometerEnabled));
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import static io.quarkiverse.temporal.Constants.DEFAULT_WORKER_NAME;

import java.time.Duration;
import java.util.Map;
import java.util.Optional;

Expand All @@ -12,6 +13,7 @@
import io.smallrye.config.ConfigMapping;
import io.smallrye.config.WithDefault;
import io.smallrye.config.WithDefaults;
import io.smallrye.config.WithName;
import io.smallrye.config.WithUnnamedKey;

@ConfigMapping(prefix = "quarkus.temporal")
Expand All @@ -37,6 +39,20 @@ public interface TemporalRuntimeConfig {
@ConfigDocSection
ConnectionRuntimeConfig connection();

/**
* Enable Micrometer, enabled by default if Micrometer capability is detected.
*/
@WithName("metrics.enabled")
@WithDefault("true")
boolean metricsEnabled();

/**
* The interval at which we report metrics to the metric registry. Default is 15 seconds.
*/
@WithName("metrics.report.duration")
@WithDefault("15s")
Duration metricsReportInterval();

/**
* Workers Configuration.
*/
Expand All @@ -52,4 +68,4 @@ public interface TemporalRuntimeConfig {
@WithDefaults
@WithUnnamedKey(DEFAULT_WORKER_NAME)
Map<String, WorkflowRuntimeConfig> workflow();
}
}
4 changes: 4 additions & 0 deletions integration-tests/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-opentelemetry</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-micrometer-registry-prometheus</artifactId>
</dependency>
<dependency>
<groupId>io.quarkiverse.temporal</groupId>
<artifactId>quarkus-temporal</artifactId>
Expand Down

0 comments on commit 2ac2483

Please sign in to comment.