@temporalio/core-bridge 0.19.2 → 0.20.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/Cargo.lock +90 -157
  2. package/Cargo.toml +1 -0
  3. package/index.d.ts +11 -27
  4. package/package.json +3 -3
  5. package/releases/aarch64-apple-darwin/index.node +0 -0
  6. package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
  7. package/releases/x86_64-apple-darwin/index.node +0 -0
  8. package/releases/x86_64-pc-windows-msvc/index.node +0 -0
  9. package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
  10. package/sdk-core/.buildkite/docker/Dockerfile +1 -1
  11. package/sdk-core/.buildkite/docker/docker-compose.yaml +1 -1
  12. package/sdk-core/.cargo/config.toml +1 -0
  13. package/sdk-core/CODEOWNERS +1 -1
  14. package/sdk-core/bridge-ffi/include/sdk-core-bridge.h +119 -86
  15. package/sdk-core/bridge-ffi/src/lib.rs +311 -315
  16. package/sdk-core/bridge-ffi/src/wrappers.rs +108 -113
  17. package/sdk-core/client/Cargo.toml +13 -9
  18. package/sdk-core/client/LICENSE.txt +23 -0
  19. package/sdk-core/client/src/lib.rs +286 -174
  20. package/sdk-core/client/src/metrics.rs +86 -12
  21. package/sdk-core/client/src/raw.rs +566 -0
  22. package/sdk-core/client/src/retry.rs +137 -99
  23. package/sdk-core/core/Cargo.toml +15 -10
  24. package/sdk-core/core/LICENSE.txt +23 -0
  25. package/sdk-core/core/benches/workflow_replay.rs +79 -0
  26. package/sdk-core/core/src/abstractions.rs +38 -0
  27. package/sdk-core/core/src/core_tests/activity_tasks.rs +108 -182
  28. package/sdk-core/core/src/core_tests/child_workflows.rs +16 -11
  29. package/sdk-core/core/src/core_tests/determinism.rs +24 -12
  30. package/sdk-core/core/src/core_tests/local_activities.rs +53 -27
  31. package/sdk-core/core/src/core_tests/mod.rs +30 -43
  32. package/sdk-core/core/src/core_tests/queries.rs +82 -81
  33. package/sdk-core/core/src/core_tests/workers.rs +111 -296
  34. package/sdk-core/core/src/core_tests/workflow_cancels.rs +4 -4
  35. package/sdk-core/core/src/core_tests/workflow_tasks.rs +257 -242
  36. package/sdk-core/core/src/lib.rs +73 -318
  37. package/sdk-core/core/src/pollers/mod.rs +4 -6
  38. package/sdk-core/core/src/pollers/poll_buffer.rs +20 -14
  39. package/sdk-core/core/src/protosext/mod.rs +7 -10
  40. package/sdk-core/core/src/replay/mod.rs +11 -150
  41. package/sdk-core/core/src/telemetry/metrics.rs +35 -2
  42. package/sdk-core/core/src/telemetry/mod.rs +49 -16
  43. package/sdk-core/core/src/telemetry/prometheus_server.rs +14 -35
  44. package/sdk-core/core/src/test_help/mod.rs +104 -170
  45. package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +57 -34
  46. package/sdk-core/core/src/worker/activities/local_activities.rs +95 -23
  47. package/sdk-core/core/src/worker/activities.rs +23 -16
  48. package/sdk-core/core/src/worker/client/mocks.rs +86 -0
  49. package/sdk-core/core/src/worker/client.rs +209 -0
  50. package/sdk-core/core/src/worker/mod.rs +207 -108
  51. package/sdk-core/core/src/workflow/driven_workflow.rs +21 -6
  52. package/sdk-core/core/src/workflow/history_update.rs +107 -24
  53. package/sdk-core/core/src/workflow/machines/activity_state_machine.rs +2 -3
  54. package/sdk-core/core/src/workflow/machines/child_workflow_state_machine.rs +2 -3
  55. package/sdk-core/core/src/workflow/machines/mod.rs +20 -17
  56. package/sdk-core/core/src/workflow/machines/signal_external_state_machine.rs +56 -19
  57. package/sdk-core/core/src/workflow/machines/transition_coverage.rs +5 -0
  58. package/sdk-core/core/src/workflow/machines/upsert_search_attributes_state_machine.rs +230 -22
  59. package/sdk-core/core/src/workflow/machines/workflow_machines.rs +81 -115
  60. package/sdk-core/core/src/workflow/machines/workflow_task_state_machine.rs +4 -4
  61. package/sdk-core/core/src/workflow/mod.rs +13 -1
  62. package/sdk-core/core/src/workflow/workflow_tasks/concurrency_manager.rs +70 -11
  63. package/sdk-core/core/src/workflow/workflow_tasks/mod.rs +65 -41
  64. package/sdk-core/core-api/Cargo.toml +9 -1
  65. package/sdk-core/core-api/LICENSE.txt +23 -0
  66. package/sdk-core/core-api/src/errors.rs +7 -38
  67. package/sdk-core/core-api/src/lib.rs +44 -52
  68. package/sdk-core/core-api/src/worker.rs +10 -2
  69. package/sdk-core/etc/deps.svg +127 -96
  70. package/sdk-core/protos/api_upstream/temporal/api/command/v1/message.proto +11 -7
  71. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +10 -0
  72. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/namespace.proto +6 -1
  73. package/sdk-core/protos/api_upstream/temporal/api/enums/v1/workflow.proto +6 -0
  74. package/sdk-core/protos/api_upstream/temporal/api/errordetails/v1/message.proto +6 -0
  75. package/sdk-core/protos/api_upstream/temporal/api/history/v1/message.proto +2 -1
  76. package/sdk-core/protos/api_upstream/temporal/api/replication/v1/message.proto +3 -0
  77. package/sdk-core/protos/api_upstream/temporal/api/workflow/v1/message.proto +12 -0
  78. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +25 -0
  79. package/sdk-core/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +4 -0
  80. package/sdk-core/protos/local/temporal/sdk/core/bridge/bridge.proto +19 -35
  81. package/sdk-core/protos/local/temporal/sdk/core/core_interface.proto +2 -6
  82. package/sdk-core/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +53 -11
  83. package/sdk-core/protos/local/temporal/sdk/core/workflow_commands/workflow_commands.proto +14 -7
  84. package/sdk-core/protos/local/temporal/sdk/core/workflow_completion/workflow_completion.proto +3 -5
  85. package/sdk-core/sdk/Cargo.toml +16 -2
  86. package/sdk-core/sdk/LICENSE.txt +23 -0
  87. package/sdk-core/sdk/src/interceptors.rs +11 -0
  88. package/sdk-core/sdk/src/lib.rs +139 -151
  89. package/sdk-core/sdk/src/workflow_context/options.rs +86 -1
  90. package/sdk-core/sdk/src/workflow_context.rs +36 -17
  91. package/sdk-core/sdk/src/workflow_future.rs +19 -25
  92. package/sdk-core/sdk-core-protos/Cargo.toml +1 -1
  93. package/sdk-core/sdk-core-protos/build.rs +1 -0
  94. package/sdk-core/sdk-core-protos/src/history_info.rs +17 -4
  95. package/sdk-core/sdk-core-protos/src/lib.rs +251 -47
  96. package/sdk-core/test-utils/Cargo.toml +3 -1
  97. package/sdk-core/test-utils/src/canned_histories.rs +27 -0
  98. package/sdk-core/test-utils/src/histfetch.rs +3 -3
  99. package/sdk-core/test-utils/src/lib.rs +223 -68
  100. package/sdk-core/tests/integ_tests/client_tests.rs +27 -4
  101. package/sdk-core/tests/integ_tests/heartbeat_tests.rs +93 -14
  102. package/sdk-core/tests/integ_tests/polling_tests.rs +18 -12
  103. package/sdk-core/tests/integ_tests/queries_tests.rs +50 -53
  104. package/sdk-core/tests/integ_tests/workflow_tests/activities.rs +117 -103
  105. package/sdk-core/tests/integ_tests/workflow_tests/cancel_external.rs +8 -1
  106. package/sdk-core/tests/integ_tests/workflow_tests/cancel_wf.rs +10 -5
  107. package/sdk-core/tests/integ_tests/workflow_tests/child_workflows.rs +7 -1
  108. package/sdk-core/tests/integ_tests/workflow_tests/continue_as_new.rs +32 -9
  109. package/sdk-core/tests/integ_tests/workflow_tests/determinism.rs +7 -1
  110. package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +76 -15
  111. package/sdk-core/tests/integ_tests/workflow_tests/patches.rs +19 -3
  112. package/sdk-core/tests/integ_tests/workflow_tests/replay.rs +39 -42
  113. package/sdk-core/tests/integ_tests/workflow_tests/resets.rs +84 -0
  114. package/sdk-core/tests/integ_tests/workflow_tests/signals.rs +30 -8
  115. package/sdk-core/tests/integ_tests/workflow_tests/stickyness.rs +21 -6
  116. package/sdk-core/tests/integ_tests/workflow_tests/timers.rs +26 -16
  117. package/sdk-core/tests/integ_tests/workflow_tests/upsert_search_attrs.rs +66 -0
  118. package/sdk-core/tests/integ_tests/workflow_tests.rs +78 -74
  119. package/sdk-core/tests/load_tests.rs +9 -6
  120. package/sdk-core/tests/main.rs +43 -10
  121. package/src/conversions.rs +7 -12
  122. package/src/lib.rs +322 -357
  123. package/sdk-core/client/src/mocks.rs +0 -167
  124. package/sdk-core/core/src/worker/dispatcher.rs +0 -171
  125. package/sdk-core/protos/local/temporal/sdk/core/bridge/service.proto +0 -61
@@ -2,7 +2,7 @@
2
2
  //! to replay canned histories. It should be used by Lang SDKs to provide replay capabilities to
3
3
  //! users during testing.
4
4
 
5
- use crate::{init_mock_gateway, CoreInitOptionsBuilder, CoreSDK, TelemetryOptions};
5
+ use crate::{worker::client::mocks::mock_manual_workflow_client, WorkerClientBag};
6
6
  use futures::FutureExt;
7
7
  use std::{
8
8
  sync::{
@@ -11,154 +11,26 @@ use std::{
11
11
  },
12
12
  time::Duration,
13
13
  };
14
- use temporal_client::{
15
- mocks::{mock_gateway, mock_manual_gateway},
16
- ServerGatewayApis,
17
- };
18
- use temporal_sdk_core_api::{
19
- errors::{
20
- CompleteActivityError, CompleteWfError, PollActivityError, PollWfError,
21
- WorkerRegistrationError,
22
- },
23
- worker::WorkerConfig,
24
- Core, CoreLog,
25
- };
26
- use temporal_sdk_core_protos::{
27
- coresdk::{
28
- activity_task::ActivityTask, workflow_activation::WorkflowActivation,
29
- workflow_completion::WorkflowActivationCompletion, ActivityHeartbeat,
30
- ActivityTaskCompletion,
31
- },
32
- temporal::api::{
33
- common::v1::WorkflowExecution,
34
- history::v1::History,
35
- workflowservice::v1::{
36
- RespondWorkflowTaskCompletedResponse, RespondWorkflowTaskFailedResponse,
37
- StartWorkflowExecutionResponse,
38
- },
14
+ use temporal_sdk_core_protos::temporal::api::{
15
+ common::v1::WorkflowExecution,
16
+ history::v1::History,
17
+ workflowservice::v1::{
18
+ RespondWorkflowTaskCompletedResponse, RespondWorkflowTaskFailedResponse,
39
19
  },
40
20
  };
41
-
42
21
  pub use temporal_sdk_core_protos::{
43
22
  default_wes_attribs, HistoryInfo, TestHistoryBuilder, DEFAULT_WORKFLOW_TYPE,
44
23
  };
45
24
 
46
- /// Create a core instance that can be used for replay. See the [ReplayCore] trait for adding
47
- /// canned history.
48
- pub fn init_core_replay(opts: TelemetryOptions) -> ReplayCoreImpl {
49
- let shared_mock_gateway = mock_gateway();
50
- let init_opts = CoreInitOptionsBuilder::default()
51
- .gateway_opts(shared_mock_gateway.get_options().clone())
52
- .telemetry_opts(opts)
53
- .build()
54
- .expect("replay core options init properly");
55
- let replay_core =
56
- init_mock_gateway(init_opts, shared_mock_gateway).expect("init replay core works");
57
- ReplayCoreImpl { inner: replay_core }
58
- }
59
-
60
- /// An extension of the [Core] trait to be used for testing workflows against canned histories.
61
- pub trait ReplayCore: Core {
62
- /// Make a fake worker which will use the provided history to simulate poll responses containing
63
- /// that entire history. The configuration should have a unique task queue name.
64
- ///
65
- /// Note that some of the worker config options do not apply, and some will be overridden.
66
- /// Replay workers always are cached, have only 1 poller, and do not poll for activities.
67
- fn make_replay_worker(
68
- &self,
69
- config: WorkerConfig,
70
- history: &History,
71
- ) -> Result<(), anyhow::Error>;
72
- }
73
-
74
- /// Implements [ReplayCore] functionality
75
- pub struct ReplayCoreImpl {
76
- pub(crate) inner: CoreSDK,
77
- }
78
-
79
- impl ReplayCore for ReplayCoreImpl {
80
- fn make_replay_worker(
81
- &self,
82
- mut config: WorkerConfig,
83
- history: &History,
84
- ) -> Result<(), anyhow::Error> {
85
- let mock_g = mock_gateway_from_history(history, config.task_queue.clone());
86
- config.max_cached_workflows = 1;
87
- config.max_concurrent_wft_polls = 1;
88
- config.no_remote_activities = true;
89
- self.inner
90
- .register_replay_worker(config, Arc::new(mock_g), history)
91
- }
92
- }
93
-
94
- #[async_trait::async_trait]
95
- impl Core for ReplayCoreImpl {
96
- fn register_worker(&self, _config: WorkerConfig) -> Result<(), WorkerRegistrationError> {
97
- panic!("Do not use `register_worker` with a replay core instance")
98
- }
99
-
100
- async fn poll_workflow_activation(
101
- &self,
102
- task_queue: &str,
103
- ) -> Result<WorkflowActivation, PollWfError> {
104
- self.inner.poll_workflow_activation(task_queue).await
105
- }
106
-
107
- async fn poll_activity_task(
108
- &self,
109
- task_queue: &str,
110
- ) -> Result<ActivityTask, PollActivityError> {
111
- self.inner.poll_activity_task(task_queue).await
112
- }
113
-
114
- async fn complete_workflow_activation(
115
- &self,
116
- completion: WorkflowActivationCompletion,
117
- ) -> Result<(), CompleteWfError> {
118
- self.inner.complete_workflow_activation(completion).await
119
- }
120
-
121
- async fn complete_activity_task(
122
- &self,
123
- completion: ActivityTaskCompletion,
124
- ) -> Result<(), CompleteActivityError> {
125
- self.inner.complete_activity_task(completion).await
126
- }
127
-
128
- fn record_activity_heartbeat(&self, _details: ActivityHeartbeat) {
129
- // do nothing
130
- }
131
-
132
- fn request_workflow_eviction(&self, task_queue: &str, run_id: &str) {
133
- self.inner.request_workflow_eviction(task_queue, run_id)
134
- }
135
-
136
- fn server_gateway(&self) -> Arc<dyn ServerGatewayApis + Send + Sync> {
137
- self.inner.server_gateway()
138
- }
139
-
140
- async fn shutdown(&self) {
141
- self.inner.shutdown().await
142
- }
143
-
144
- async fn shutdown_worker(&self, task_queue: &str) {
145
- self.inner.shutdown_worker(task_queue).await
146
- }
147
-
148
- fn fetch_buffered_logs(&self) -> Vec<CoreLog> {
149
- self.inner.fetch_buffered_logs()
150
- }
151
- }
152
-
153
- /// Create a mock gateway which can be used by a replay worker to serve up canned history.
25
+ /// Create a mock client which can be used by a replay worker to serve up canned history.
154
26
  /// It will return the entire history in one workflow task, after that it will return default
155
27
  /// responses (with a 10s wait). If a workflow task failure is sent to the mock, it will send
156
28
  /// the complete response again.
157
- pub fn mock_gateway_from_history(
29
+ pub(crate) fn mock_client_from_history(
158
30
  history: &History,
159
31
  task_queue: impl Into<String>,
160
- ) -> impl ServerGatewayApis {
161
- let mut mg = mock_manual_gateway();
32
+ ) -> WorkerClientBag {
33
+ let mut mg = mock_manual_workflow_client();
162
34
 
163
35
  let hist_info = HistoryInfo::new_from_history(history, None).unwrap();
164
36
  let wf = WorkflowExecution {
@@ -166,17 +38,6 @@ pub fn mock_gateway_from_history(
166
38
  run_id: hist_info.orig_run_id().to_string(),
167
39
  };
168
40
 
169
- let wf_clone = wf.clone();
170
- mg.expect_start_workflow().returning(move |_, _, _, _, _| {
171
- let wf_clone = wf_clone.clone();
172
- async move {
173
- Ok(StartWorkflowExecutionResponse {
174
- run_id: wf_clone.run_id.clone(),
175
- })
176
- }
177
- .boxed()
178
- });
179
-
180
41
  let did_send = Arc::new(AtomicBool::new(false));
181
42
  let did_send_clone = did_send.clone();
182
43
  let tq = task_queue.into();
@@ -206,5 +67,5 @@ pub fn mock_gateway_from_history(
206
67
  async move { Ok(RespondWorkflowTaskFailedResponse {}) }.boxed()
207
68
  });
208
69
 
209
- mg
70
+ WorkerClientBag::new(Box::new(mg), "fake_namespace".to_string())
210
71
  }
@@ -8,7 +8,7 @@ use opentelemetry::{
8
8
  },
9
9
  KeyValue,
10
10
  };
11
- use std::{sync::Arc, time::Duration};
11
+ use std::{borrow::Cow, sync::Arc, time::Duration};
12
12
 
13
13
  /// Used to track context associated with metrics, and record/update them
14
14
  ///
@@ -31,6 +31,11 @@ impl MetricsContext {
31
31
  Self::new(vec![KeyValue::new(KEY_NAMESPACE, namespace)])
32
32
  }
33
33
 
34
+ pub(crate) fn with_task_q(mut self, tq: String) -> Self {
35
+ Arc::make_mut(&mut self.kvs).push(task_queue(tq));
36
+ self
37
+ }
38
+
34
39
  /// Extend an existing metrics context with new attributes
35
40
  pub(crate) fn with_new_attrs(&self, new_kvs: impl IntoIterator<Item = KeyValue>) -> Self {
36
41
  let mut kvs = self.kvs.clone();
@@ -119,6 +124,11 @@ impl MetricsContext {
119
124
  WORKER_REGISTERED.add(1, &self.kvs);
120
125
  }
121
126
 
127
+ /// Record current number of available task slots. Context should have worker type set.
128
+ pub(crate) fn available_task_slots(&self, num: usize) {
129
+ TASK_SLOTS_AVAILABLE.record(num as u64, &self.kvs)
130
+ }
131
+
122
132
  /// Record current number of pollers. Context should include poller type / task queue tag.
123
133
  pub(crate) fn record_num_pollers(&self, num: usize) {
124
134
  NUM_POLLERS.record(num as u64, &self.kvs);
@@ -174,6 +184,7 @@ const KEY_WF_TYPE: &str = "workflow_type";
174
184
  const KEY_TASK_QUEUE: &str = "task_queue";
175
185
  const KEY_ACT_TYPE: &str = "activity_type";
176
186
  const KEY_POLLER_TYPE: &str = "poller_type";
187
+ const KEY_WORKER_TYPE: &str = "worker_type";
177
188
 
178
189
  pub(crate) fn workflow_poller() -> KeyValue {
179
190
  KeyValue::new(KEY_POLLER_TYPE, "workflow_task")
@@ -193,6 +204,24 @@ pub(crate) fn activity_type(ty: String) -> KeyValue {
193
204
  pub(crate) fn workflow_type(ty: String) -> KeyValue {
194
205
  KeyValue::new(KEY_WF_TYPE, ty)
195
206
  }
207
+ pub(crate) const fn workflow_worker_type() -> KeyValue {
208
+ KeyValue {
209
+ key: opentelemetry::Key::from_static_str(KEY_WORKER_TYPE),
210
+ value: opentelemetry::Value::String(Cow::Borrowed("WorkflowWorker")),
211
+ }
212
+ }
213
+ pub(crate) const fn activity_worker_type() -> KeyValue {
214
+ KeyValue {
215
+ key: opentelemetry::Key::from_static_str(KEY_WORKER_TYPE),
216
+ value: opentelemetry::Value::String(Cow::Borrowed("ActivityWorker")),
217
+ }
218
+ }
219
+ pub(crate) const fn local_activity_worker_type() -> KeyValue {
220
+ KeyValue {
221
+ key: opentelemetry::Key::from_static_str(KEY_WORKER_TYPE),
222
+ value: opentelemetry::Value::String(Cow::Borrowed("LocalActivityWorker")),
223
+ }
224
+ }
196
225
 
197
226
  tm!(ctr, WF_COMPLETED_COUNTER, "workflow_completed");
198
227
  tm!(ctr, WF_CANCELED_COUNTER, "workflow_canceled");
@@ -248,6 +277,8 @@ tm!(vr_u64, ACT_EXEC_LATENCY, ACT_EXEC_LATENCY_NAME);
248
277
  tm!(ctr, WORKER_REGISTERED, "worker_start");
249
278
  const NUM_POLLERS_NAME: &str = "num_pollers";
250
279
  tm!(vr_u64, NUM_POLLERS, NUM_POLLERS_NAME);
280
+ const TASK_SLOTS_AVAILABLE_NAME: &str = "worker_task_slots_available";
281
+ tm!(vr_u64, TASK_SLOTS_AVAILABLE, TASK_SLOTS_AVAILABLE_NAME);
251
282
 
252
283
  tm!(ctr, STICKY_CACHE_HIT, "sticky_cache_hit");
253
284
  tm!(ctr, STICKY_CACHE_MISS, "sticky_cache_miss");
@@ -305,7 +336,9 @@ impl AggregatorSelector for SDKAggSelector {
305
336
  if *descriptor.instrument_kind() == InstrumentKind::ValueRecorder {
306
337
  // Some recorders are just gauges
307
338
  match descriptor.name() {
308
- STICKY_CACHE_SIZE_NAME | NUM_POLLERS_NAME => return Some(Arc::new(last_value())),
339
+ STICKY_CACHE_SIZE_NAME | NUM_POLLERS_NAME | TASK_SLOTS_AVAILABLE_NAME => {
340
+ return Some(Arc::new(last_value()))
341
+ }
309
342
  _ => (),
310
343
  }
311
344
 
@@ -4,13 +4,14 @@ mod prometheus_server;
4
4
  use crate::{
5
5
  log_export::CoreExportLogger,
6
6
  telemetry::{metrics::SDKAggSelector, prometheus_server::PromServer},
7
- CoreLog,
7
+ CoreLog, METRIC_METER,
8
8
  };
9
9
  use itertools::Itertools;
10
10
  use log::LevelFilter;
11
11
  use once_cell::sync::OnceCell;
12
12
  use opentelemetry::{
13
13
  global,
14
+ metrics::Meter,
14
15
  sdk::{metrics::PushController, trace::Config, Resource},
15
16
  util::tokio_interval_stream,
16
17
  KeyValue,
@@ -18,6 +19,7 @@ use opentelemetry::{
18
19
  use opentelemetry_otlp::WithExportConfig;
19
20
  use parking_lot::{const_mutex, Mutex};
20
21
  use std::{collections::VecDeque, net::SocketAddr, time::Duration};
22
+ use temporal_sdk_core_api::CoreTelemetry;
21
23
  use tracing_subscriber::{layer::SubscriberExt, EnvFilter};
22
24
  use url::Url;
23
25
 
@@ -27,6 +29,14 @@ static DEFAULT_FILTER: &str = "temporal_sdk_core=INFO";
27
29
  static GLOBAL_TELEM_DAT: OnceCell<GlobalTelemDat> = OnceCell::new();
28
30
  static TELETM_MUTEX: Mutex<()> = const_mutex(());
29
31
 
32
+ fn default_resource_kvs() -> &'static [KeyValue] {
33
+ static INSTANCE: OnceCell<[KeyValue; 1]> = OnceCell::new();
34
+ INSTANCE.get_or_init(|| [KeyValue::new("service.name", TELEM_SERVICE_NAME)])
35
+ }
36
+ fn default_resource() -> Resource {
37
+ Resource::new(default_resource_kvs().iter().cloned())
38
+ }
39
+
30
40
  /// Telemetry configuration options. Construct with [TelemetryOptionsBuilder]
31
41
  #[derive(Debug, Clone, derive_builder::Builder)]
32
42
  #[non_exhaustive]
@@ -56,6 +66,10 @@ pub struct TelemetryOptions {
56
66
  /// to the OTel collector if it is also set, only traces will be.
57
67
  #[builder(setter(into, strip_option), default)]
58
68
  pub prometheus_export_bind_address: Option<SocketAddr>,
69
+ /// If set, no resources are dedicated to telemetry and no metrics or traces are emited.
70
+ /// Supercedes all other options.
71
+ #[builder(default)]
72
+ pub totally_disable: bool,
59
73
  }
60
74
 
61
75
  impl Default for TelemetryOptions {
@@ -66,7 +80,7 @@ impl Default for TelemetryOptions {
66
80
 
67
81
  /// Things that need to not be dropped while telemetry is ongoing
68
82
  #[derive(Default)]
69
- pub(crate) struct GlobalTelemDat {
83
+ pub struct GlobalTelemDat {
70
84
  metric_push_controller: Option<PushController>,
71
85
  core_export_logger: Option<CoreExportLogger>,
72
86
  runtime: Option<tokio::runtime::Runtime>,
@@ -87,14 +101,24 @@ impl GlobalTelemDat {
87
101
  }
88
102
  }
89
103
 
90
- /// Initialize tracing subscribers and output. Core [crate::init] calls this, but it may be called
91
- /// separately so that tests may choose to initialize tracing differently. If this function is
92
- /// called more than once, subsequent calls do nothing.
104
+ impl CoreTelemetry for GlobalTelemDat {
105
+ fn fetch_buffered_logs(&self) -> Vec<CoreLog> {
106
+ fetch_global_buffered_logs()
107
+ }
108
+
109
+ fn get_metric_meter(&self) -> Option<&Meter> {
110
+ if GLOBAL_TELEM_DAT.get().is_some() {
111
+ return Some(&METRIC_METER);
112
+ }
113
+ None
114
+ }
115
+ }
116
+
117
+ /// Initialize tracing subscribers/output and logging export. If this function is called more than
118
+ /// once, subsequent calls do nothing.
93
119
  ///
94
120
  /// See [TelemetryOptions] docs for more on configuration.
95
- pub(crate) fn telemetry_init(
96
- opts: &TelemetryOptions,
97
- ) -> Result<&'static GlobalTelemDat, anyhow::Error> {
121
+ pub fn telemetry_init(opts: &TelemetryOptions) -> Result<&'static GlobalTelemDat, anyhow::Error> {
98
122
  // TODO: Per-layer filtering has been implemented but does not yet support
99
123
  // env-filter. When it does, allow filtering logs/telemetry separately.
100
124
 
@@ -116,6 +140,15 @@ pub(crate) fn telemetry_init(
116
140
  // Ensure closure captures the mutex guard
117
141
  let _ = &*guard;
118
142
 
143
+ if opts.totally_disable {
144
+ return Ok(GlobalTelemDat {
145
+ metric_push_controller: None,
146
+ core_export_logger: None,
147
+ runtime: None,
148
+ prom_srv: None,
149
+ });
150
+ }
151
+
119
152
  let runtime = tokio::runtime::Builder::new_multi_thread()
120
153
  .thread_name("telemetry")
121
154
  .worker_threads(2)
@@ -146,11 +179,7 @@ pub(crate) fn telemetry_init(
146
179
 
147
180
  if let Some(otel_url) = opts.otel_collector_url.as_ref() {
148
181
  runtime.block_on(async {
149
- let tracer_cfg =
150
- Config::default().with_resource(Resource::new(vec![KeyValue::new(
151
- "service.name",
152
- TELEM_SERVICE_NAME,
153
- )]));
182
+ let tracer_cfg = Config::default().with_resource(default_resource());
154
183
  let tracer = opentelemetry_otlp::new_pipeline()
155
184
  .tracing()
156
185
  .with_exporter(
@@ -168,6 +197,7 @@ pub(crate) fn telemetry_init(
168
197
  .metrics(|f| runtime.spawn(f), tokio_interval_stream)
169
198
  .with_aggregator_selector(SDKAggSelector)
170
199
  .with_period(Duration::from_secs(1))
200
+ .with_resource(default_resource_kvs().iter().cloned())
171
201
  .with_exporter(
172
202
  // No joke exporter builder literally not cloneable for some insane
173
203
  // reason
@@ -210,8 +240,9 @@ pub(crate) fn telemetry_init(
210
240
  .expect("Telemetry initialization panicked")
211
241
  }
212
242
 
213
- /// Returned buffered logs for export to lang from the global logging instance
214
- pub(crate) fn fetch_global_buffered_logs() -> Vec<CoreLog> {
243
+ /// Returned buffered logs for export to lang from the global logging instance.
244
+ /// If [telemetry_init] has not been called, always returns an empty vec.
245
+ pub fn fetch_global_buffered_logs() -> Vec<CoreLog> {
215
246
  if let Some(loggr) = GLOBAL_TELEM_DAT
216
247
  .get()
217
248
  .and_then(|gd| gd.core_export_logger.as_ref())
@@ -227,9 +258,10 @@ pub(crate) fn fetch_global_buffered_logs() -> Vec<CoreLog> {
227
258
  pub(crate) fn test_telem_console() {
228
259
  telemetry_init(&TelemetryOptions {
229
260
  otel_collector_url: None,
230
- tracing_filter: "temporal_sdk_core=DEBUG".to_string(),
261
+ tracing_filter: "temporal_sdk_core=DEBUG,temporal_sdk=DEBUG".to_string(),
231
262
  log_forwarding_level: LevelFilter::Off,
232
263
  prometheus_export_bind_address: None,
264
+ totally_disable: false,
233
265
  })
234
266
  .unwrap();
235
267
  }
@@ -242,6 +274,7 @@ pub(crate) fn test_telem_collector() {
242
274
  tracing_filter: "temporal_sdk_core=DEBUG".to_string(),
243
275
  log_forwarding_level: LevelFilter::Off,
244
276
  prometheus_export_bind_address: None,
277
+ totally_disable: false,
245
278
  })
246
279
  .unwrap();
247
280
  }
@@ -1,17 +1,16 @@
1
- use crate::telemetry::metrics::{SDKAggSelector, DEFAULT_MS_BUCKETS};
1
+ use crate::telemetry::{
2
+ default_resource,
3
+ metrics::{SDKAggSelector, DEFAULT_MS_BUCKETS},
4
+ };
2
5
  use hyper::{
3
6
  header::CONTENT_TYPE,
4
7
  service::{make_service_fn, service_fn},
5
8
  Body, Method, Request, Response, Server,
6
9
  };
7
- use opentelemetry::{
8
- global,
9
- metrics::MetricsError,
10
- sdk::{export::metrics::ExportKindSelector, metrics::controllers},
11
- };
12
- use opentelemetry_prometheus::PrometheusExporter;
10
+ use opentelemetry::metrics::MetricsError;
11
+ use opentelemetry_prometheus::{ExporterBuilder, PrometheusExporter};
13
12
  use prometheus::{Encoder, TextEncoder};
14
- use std::{convert::Infallible, net::SocketAddr, sync::Arc, time::Duration};
13
+ use std::{convert::Infallible, net::SocketAddr, sync::Arc};
15
14
 
16
15
  /// Exposes prometheus metrics for scraping
17
16
  pub(super) struct PromServer {
@@ -21,7 +20,13 @@ pub(super) struct PromServer {
21
20
 
22
21
  impl PromServer {
23
22
  pub fn new(addr: SocketAddr) -> Result<Self, MetricsError> {
24
- let exporter = create_exporter()?;
23
+ let exporter = ExporterBuilder::default()
24
+ .with_default_histogram_boundaries(DEFAULT_MS_BUCKETS.to_vec())
25
+ .with_aggregator_selector(SDKAggSelector)
26
+ .with_host(addr.ip().to_string())
27
+ .with_port(addr.port())
28
+ .with_resource(default_resource())
29
+ .try_init()?;
25
30
  Ok(Self {
26
31
  exporter: Arc::new(exporter),
27
32
  addr,
@@ -66,29 +71,3 @@ async fn metrics_req(
66
71
  };
67
72
  Ok(response)
68
73
  }
69
-
70
- /// There is no easy way to customize the aggregation selector for the prom exporter so this
71
- /// code is some dupe of the exporter's try_init code.
72
- pub fn create_exporter() -> Result<PrometheusExporter, MetricsError> {
73
- let controller_builder = controllers::pull(
74
- Box::new(SDKAggSelector),
75
- Box::new(ExportKindSelector::Cumulative),
76
- )
77
- .with_cache_period(Duration::from_secs(0))
78
- .with_memory(true);
79
- let controller = controller_builder.build();
80
-
81
- global::set_meter_provider(controller.provider());
82
-
83
- // No choice bro https://github.com/open-telemetry/opentelemetry-rust/issues/633
84
- #[allow(deprecated)]
85
- PrometheusExporter::new(
86
- prometheus::Registry::new(),
87
- controller,
88
- DEFAULT_MS_BUCKETS.to_vec(),
89
- DEFAULT_MS_BUCKETS.to_vec(),
90
- // Host and port aren't actually used for anything
91
- "".to_string(),
92
- 0,
93
- )
94
- }