@temporalio/core-bridge 1.12.0 → 1.12.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 (116) hide show
  1. package/Cargo.lock +64 -119
  2. package/Cargo.toml +1 -1
  3. package/index.js +3 -2
  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/.cargo/config.toml +1 -2
  11. package/sdk-core/.github/workflows/per-pr.yml +2 -0
  12. package/sdk-core/AGENTS.md +7 -0
  13. package/sdk-core/Cargo.toml +9 -5
  14. package/sdk-core/README.md +6 -5
  15. package/sdk-core/client/Cargo.toml +3 -2
  16. package/sdk-core/client/src/lib.rs +17 -8
  17. package/sdk-core/client/src/metrics.rs +57 -23
  18. package/sdk-core/client/src/raw.rs +33 -15
  19. package/sdk-core/core/Cargo.toml +11 -9
  20. package/sdk-core/core/benches/workflow_replay.rs +114 -15
  21. package/sdk-core/core/src/core_tests/activity_tasks.rs +18 -18
  22. package/sdk-core/core/src/core_tests/child_workflows.rs +4 -4
  23. package/sdk-core/core/src/core_tests/determinism.rs +6 -6
  24. package/sdk-core/core/src/core_tests/local_activities.rs +20 -20
  25. package/sdk-core/core/src/core_tests/mod.rs +40 -5
  26. package/sdk-core/core/src/core_tests/queries.rs +25 -16
  27. package/sdk-core/core/src/core_tests/replay_flag.rs +3 -3
  28. package/sdk-core/core/src/core_tests/updates.rs +3 -3
  29. package/sdk-core/core/src/core_tests/workers.rs +9 -7
  30. package/sdk-core/core/src/core_tests/workflow_tasks.rs +40 -42
  31. package/sdk-core/core/src/ephemeral_server/mod.rs +1 -19
  32. package/sdk-core/core/src/lib.rs +10 -1
  33. package/sdk-core/core/src/pollers/poll_buffer.rs +2 -2
  34. package/sdk-core/core/src/replay/mod.rs +3 -3
  35. package/sdk-core/core/src/telemetry/metrics.rs +306 -152
  36. package/sdk-core/core/src/telemetry/mod.rs +11 -4
  37. package/sdk-core/core/src/telemetry/otel.rs +134 -131
  38. package/sdk-core/core/src/telemetry/prometheus_meter.rs +885 -0
  39. package/sdk-core/core/src/telemetry/prometheus_server.rs +48 -28
  40. package/sdk-core/core/src/test_help/mod.rs +27 -12
  41. package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +7 -7
  42. package/sdk-core/core/src/worker/activities.rs +4 -4
  43. package/sdk-core/core/src/worker/client/mocks.rs +10 -3
  44. package/sdk-core/core/src/worker/client.rs +68 -5
  45. package/sdk-core/core/src/worker/heartbeat.rs +229 -0
  46. package/sdk-core/core/src/worker/mod.rs +35 -14
  47. package/sdk-core/core/src/worker/tuner/resource_based.rs +4 -4
  48. package/sdk-core/core/src/worker/workflow/history_update.rs +71 -19
  49. package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +1 -2
  50. package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +1 -1
  51. package/sdk-core/core/src/worker/workflow/machines/nexus_operation_state_machine.rs +31 -48
  52. package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +1 -2
  53. package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +3 -3
  54. package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +4 -1
  55. package/sdk-core/core/src/worker/workflow/managed_run.rs +1 -1
  56. package/sdk-core/core/src/worker/workflow/mod.rs +15 -15
  57. package/sdk-core/core-api/Cargo.toml +2 -2
  58. package/sdk-core/core-api/src/envconfig.rs +204 -99
  59. package/sdk-core/core-api/src/lib.rs +9 -0
  60. package/sdk-core/core-api/src/telemetry/metrics.rs +548 -100
  61. package/sdk-core/core-api/src/worker.rs +11 -5
  62. package/sdk-core/core-c-bridge/Cargo.toml +49 -0
  63. package/sdk-core/core-c-bridge/build.rs +26 -0
  64. package/sdk-core/core-c-bridge/include/temporal-sdk-core-c-bridge.h +817 -0
  65. package/sdk-core/core-c-bridge/src/client.rs +679 -0
  66. package/sdk-core/core-c-bridge/src/lib.rs +245 -0
  67. package/sdk-core/core-c-bridge/src/metric.rs +682 -0
  68. package/sdk-core/core-c-bridge/src/random.rs +61 -0
  69. package/sdk-core/core-c-bridge/src/runtime.rs +445 -0
  70. package/sdk-core/core-c-bridge/src/testing.rs +282 -0
  71. package/sdk-core/core-c-bridge/src/tests/context.rs +644 -0
  72. package/sdk-core/core-c-bridge/src/tests/mod.rs +178 -0
  73. package/sdk-core/core-c-bridge/src/tests/utils.rs +108 -0
  74. package/sdk-core/core-c-bridge/src/worker.rs +1069 -0
  75. package/sdk-core/etc/deps.svg +64 -64
  76. package/sdk-core/sdk/src/activity_context.rs +6 -4
  77. package/sdk-core/sdk/src/lib.rs +49 -27
  78. package/sdk-core/sdk/src/workflow_future.rs +18 -25
  79. package/sdk-core/sdk-core-protos/protos/api_upstream/README.md +4 -0
  80. package/sdk-core/sdk-core-protos/protos/api_upstream/buf.yaml +0 -2
  81. package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/openapiv2.json +630 -83
  82. package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/openapiv3.yaml +632 -78
  83. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/batch/v1/message.proto +4 -4
  84. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/command/v1/message.proto +6 -4
  85. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/common/v1/message.proto +2 -2
  86. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/deployment/v1/message.proto +32 -2
  87. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/common.proto +10 -1
  88. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/deployment.proto +26 -0
  89. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +2 -0
  90. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/reset.proto +4 -4
  91. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/failure/v1/message.proto +2 -2
  92. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/history/v1/message.proto +47 -31
  93. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/nexus/v1/message.proto +4 -4
  94. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/schedule/v1/message.proto +7 -1
  95. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/worker/v1/message.proto +134 -0
  96. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflow/v1/message.proto +14 -11
  97. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +148 -37
  98. package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +21 -0
  99. package/sdk-core/sdk-core-protos/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +4 -4
  100. package/sdk-core/sdk-core-protos/src/history_builder.rs +9 -5
  101. package/sdk-core/sdk-core-protos/src/lib.rs +96 -6
  102. package/sdk-core/test-utils/src/lib.rs +11 -3
  103. package/sdk-core/tests/cloud_tests.rs +3 -3
  104. package/sdk-core/tests/heavy_tests.rs +11 -3
  105. package/sdk-core/tests/integ_tests/client_tests.rs +12 -13
  106. package/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +1 -1
  107. package/sdk-core/tests/integ_tests/metrics_tests.rs +188 -83
  108. package/sdk-core/tests/integ_tests/polling_tests.rs +1 -1
  109. package/sdk-core/tests/integ_tests/queries_tests.rs +56 -40
  110. package/sdk-core/tests/integ_tests/update_tests.rs +2 -7
  111. package/sdk-core/tests/integ_tests/worker_tests.rs +3 -4
  112. package/sdk-core/tests/integ_tests/worker_versioning_tests.rs +3 -7
  113. package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +3 -5
  114. package/sdk-core/tests/integ_tests/workflow_tests/nexus.rs +24 -17
  115. package/src/client.rs +6 -0
  116. package/src/metrics.rs +6 -6
@@ -0,0 +1,61 @@
1
+ use crate::ByteArrayRef;
2
+ use rand::{Rng, SeedableRng};
3
+ use rand_pcg::Pcg64Mcg;
4
+
5
+ pub struct Random {
6
+ // We choose this algorithm because it is 64-bit fast and a well supported,
7
+ // deterministic, portable standard. We do not need the security of a CSPRNG
8
+ // like ChaCha20.
9
+ rand: Pcg64Mcg,
10
+ }
11
+
12
+ #[unsafe(no_mangle)]
13
+ pub extern "C" fn temporal_core_random_new(seed: u64) -> *mut Random {
14
+ Box::into_raw(Box::new(Random {
15
+ rand: Pcg64Mcg::seed_from_u64(seed),
16
+ }))
17
+ }
18
+
19
+ #[unsafe(no_mangle)]
20
+ pub extern "C" fn temporal_core_random_free(random: *mut Random) {
21
+ unsafe {
22
+ let _ = Box::from_raw(random);
23
+ }
24
+ }
25
+
26
+ #[unsafe(no_mangle)]
27
+ pub extern "C" fn temporal_core_random_int32_range(
28
+ random: *mut Random,
29
+ min: i32,
30
+ max: i32,
31
+ max_inclusive: bool,
32
+ ) -> i32 {
33
+ let random = unsafe { &mut *random };
34
+ if max_inclusive {
35
+ random.rand.gen_range(min..=max)
36
+ } else {
37
+ random.rand.gen_range(min..max)
38
+ }
39
+ }
40
+
41
+ #[unsafe(no_mangle)]
42
+ pub extern "C" fn temporal_core_random_double_range(
43
+ random: *mut Random,
44
+ min: f64,
45
+ max: f64,
46
+ max_inclusive: bool,
47
+ ) -> f64 {
48
+ let random = unsafe { &mut *random };
49
+ if max_inclusive {
50
+ random.rand.gen_range(min..=max)
51
+ } else {
52
+ random.rand.gen_range(min..max)
53
+ }
54
+ }
55
+
56
+ #[unsafe(no_mangle)]
57
+ pub extern "C" fn temporal_core_random_fill_bytes(random: *mut Random, mut bytes: ByteArrayRef) {
58
+ let random = unsafe { &mut *random };
59
+ // Confirmed with the algorithm this won't fail, so try_fill not needed
60
+ random.rand.fill(bytes.to_slice_mut());
61
+ }
@@ -0,0 +1,445 @@
1
+ use crate::ByteArray;
2
+ use crate::ByteArrayRef;
3
+ use crate::MetadataRef;
4
+ use crate::metric::CustomMetricMeter;
5
+ use crate::metric::CustomMetricMeterRef;
6
+
7
+ use serde_json::json;
8
+ use std::collections::HashMap;
9
+ use std::fmt;
10
+ use std::net::SocketAddr;
11
+ use std::str::FromStr;
12
+ use std::sync::atomic::AtomicBool;
13
+ use std::sync::atomic::Ordering;
14
+ use std::sync::{Arc, Mutex};
15
+ use std::time::Duration;
16
+ use std::time::UNIX_EPOCH;
17
+ use temporal_sdk_core::CoreRuntime;
18
+ use temporal_sdk_core::TokioRuntimeBuilder;
19
+ use temporal_sdk_core::telemetry::{build_otlp_metric_exporter, start_prometheus_metric_exporter};
20
+ use temporal_sdk_core_api::telemetry::HistogramBucketOverrides;
21
+ use temporal_sdk_core_api::telemetry::MetricTemporality;
22
+ use temporal_sdk_core_api::telemetry::metrics::CoreMeter;
23
+ use temporal_sdk_core_api::telemetry::{CoreLog, CoreLogConsumer};
24
+ use temporal_sdk_core_api::telemetry::{
25
+ Logger, OtelCollectorOptionsBuilder, PrometheusExporterOptionsBuilder,
26
+ TelemetryOptions as CoreTelemetryOptions, TelemetryOptionsBuilder,
27
+ };
28
+ use tracing::Level;
29
+ use url::Url;
30
+
31
+ #[repr(C)]
32
+ pub struct RuntimeOptions {
33
+ pub telemetry: *const TelemetryOptions,
34
+ }
35
+
36
+ #[repr(C)]
37
+ pub struct TelemetryOptions {
38
+ pub logging: *const LoggingOptions,
39
+ pub metrics: *const MetricsOptions,
40
+ }
41
+
42
+ #[repr(C)]
43
+ pub struct LoggingOptions {
44
+ pub filter: ByteArrayRef,
45
+ /// This callback is expected to work for the life of the runtime.
46
+ pub forward_to: ForwardedLogCallback,
47
+ }
48
+
49
+ // This has to be Option here because of https://github.com/mozilla/cbindgen/issues/326
50
+ /// Operations on the log can only occur within the callback, it is freed
51
+ /// immediately thereafter.
52
+ pub type ForwardedLogCallback =
53
+ Option<unsafe extern "C" fn(level: ForwardedLogLevel, log: *const ForwardedLog)>;
54
+
55
+ pub struct ForwardedLog {
56
+ core: CoreLog,
57
+ fields_json: Arc<Mutex<Option<String>>>,
58
+ }
59
+
60
+ #[repr(C)]
61
+ pub enum ForwardedLogLevel {
62
+ Trace = 0,
63
+ Debug,
64
+ Info,
65
+ Warn,
66
+ Error,
67
+ }
68
+
69
+ /// Only one of opentelemetry, prometheus, or custom_meter can be present.
70
+ #[repr(C)]
71
+ pub struct MetricsOptions {
72
+ pub opentelemetry: *const OpenTelemetryOptions,
73
+ pub prometheus: *const PrometheusOptions,
74
+ /// If present, this is freed by a callback within itself
75
+ pub custom_meter: *const CustomMetricMeter,
76
+
77
+ pub attach_service_name: bool,
78
+ pub global_tags: MetadataRef,
79
+ pub metric_prefix: ByteArrayRef,
80
+ }
81
+
82
+ #[repr(C)]
83
+ pub struct OpenTelemetryOptions {
84
+ pub url: ByteArrayRef,
85
+ pub headers: MetadataRef,
86
+ pub metric_periodicity_millis: u32,
87
+ pub metric_temporality: OpenTelemetryMetricTemporality,
88
+ pub durations_as_seconds: bool,
89
+ pub protocol: OpenTelemetryProtocol,
90
+ /// Histogram bucket overrides in form of
91
+ /// <metric1>\n<float>,<float>,<float>\n<metric2>\n<float>,<float>,<float>
92
+ pub histogram_bucket_overrides: MetadataRef,
93
+ }
94
+
95
+ #[repr(C)]
96
+ pub enum OpenTelemetryMetricTemporality {
97
+ Cumulative = 1,
98
+ Delta,
99
+ }
100
+
101
+ #[repr(C)]
102
+ pub enum OpenTelemetryProtocol {
103
+ Grpc = 1,
104
+ Http,
105
+ }
106
+
107
+ #[repr(C)]
108
+ pub struct PrometheusOptions {
109
+ pub bind_address: ByteArrayRef,
110
+ pub counters_total_suffix: bool,
111
+ pub unit_suffix: bool,
112
+ pub durations_as_seconds: bool,
113
+ /// Histogram bucket overrides in form of
114
+ /// <metric1>\n<float>,<float>,<float>\n<metric2>\n<float>,<float>,<float>
115
+ pub histogram_bucket_overrides: MetadataRef,
116
+ }
117
+
118
+ #[derive(Clone)]
119
+ pub struct Runtime {
120
+ pub(crate) core: Arc<CoreRuntime>,
121
+ log_forwarder: Option<Arc<LogForwarder>>,
122
+ }
123
+
124
+ /// If fail is not null, it must be manually freed when done. Runtime is always
125
+ /// present, but it should never be used if fail is present, only freed after
126
+ /// fail is freed using it.
127
+ #[repr(C)]
128
+ pub struct RuntimeOrFail {
129
+ pub runtime: *mut Runtime,
130
+ pub fail: *const ByteArray,
131
+ }
132
+
133
+ #[unsafe(no_mangle)]
134
+ pub extern "C" fn temporal_core_runtime_new(options: *const RuntimeOptions) -> RuntimeOrFail {
135
+ match Runtime::new(unsafe { &*options }) {
136
+ Ok(runtime) => RuntimeOrFail {
137
+ runtime: Box::into_raw(Box::new(runtime)),
138
+ fail: std::ptr::null(),
139
+ },
140
+ Err(err) => {
141
+ // We have to make an empty runtime just for the failure to be
142
+ // freeable
143
+ let mut runtime = Runtime {
144
+ core: Arc::new(
145
+ CoreRuntime::new(
146
+ CoreTelemetryOptions::default(),
147
+ TokioRuntimeBuilder::default(),
148
+ )
149
+ .unwrap(),
150
+ ),
151
+ log_forwarder: None,
152
+ };
153
+ let fail = runtime.alloc_utf8(&format!("Invalid options: {err}"));
154
+ RuntimeOrFail {
155
+ runtime: Box::into_raw(Box::new(runtime)),
156
+ fail: fail.into_raw(),
157
+ }
158
+ }
159
+ }
160
+ }
161
+
162
+ #[unsafe(no_mangle)]
163
+ pub extern "C" fn temporal_core_runtime_free(runtime: *mut Runtime) {
164
+ unsafe {
165
+ let _ = Box::from_raw(runtime);
166
+ }
167
+ }
168
+
169
+ #[unsafe(no_mangle)]
170
+ pub extern "C" fn temporal_core_byte_array_free(runtime: *mut Runtime, bytes: *const ByteArray) {
171
+ // Bail if freeing is disabled
172
+ unsafe {
173
+ if bytes.is_null() || (*bytes).disable_free {
174
+ return;
175
+ }
176
+ }
177
+ let bytes = bytes as *mut ByteArray;
178
+ // Return vec back to core before dropping bytes
179
+ let vec = unsafe { Vec::from_raw_parts((*bytes).data as *mut u8, (*bytes).size, (*bytes).cap) };
180
+ // Set to null so the byte dropper doesn't try to free it
181
+ unsafe { (*bytes).data = std::ptr::null_mut() };
182
+ // Return only if runtime is non-null
183
+ if !runtime.is_null() {
184
+ let runtime = unsafe { &mut *runtime };
185
+ runtime.return_buf(vec);
186
+ }
187
+ unsafe {
188
+ let _ = Box::from_raw(bytes);
189
+ }
190
+ }
191
+
192
+ impl Runtime {
193
+ fn new(options: &RuntimeOptions) -> anyhow::Result<Runtime> {
194
+ // Create custom meter here so it will be dropped on any error and
195
+ // therefore will call "free"
196
+ let custom_meter = unsafe {
197
+ options
198
+ .telemetry
199
+ .as_ref()
200
+ .and_then(|v| v.metrics.as_ref())
201
+ .map(|v| v.custom_meter)
202
+ .filter(|v| !v.is_null())
203
+ .map(CustomMetricMeterRef::new)
204
+ };
205
+
206
+ // Build telemetry options
207
+ let mut log_forwarder = None;
208
+ let telemetry_options = if let Some(v) = unsafe { options.telemetry.as_ref() } {
209
+ let mut build = TelemetryOptionsBuilder::default();
210
+
211
+ // Metrics options (note, metrics meter is late-bound later)
212
+ if let Some(v) = unsafe { v.metrics.as_ref() } {
213
+ build.attach_service_name(v.attach_service_name);
214
+ if let Some(metric_prefix) = v.metric_prefix.to_option_string() {
215
+ build.metric_prefix(metric_prefix);
216
+ }
217
+ }
218
+
219
+ // Logging options
220
+ if let Some(v) = unsafe { v.logging.as_ref() } {
221
+ build.logging(if let Some(callback) = v.forward_to {
222
+ let consumer = Arc::new(LogForwarder {
223
+ callback,
224
+ active: AtomicBool::new(false),
225
+ });
226
+ log_forwarder = Some(consumer.clone());
227
+ Logger::Push {
228
+ filter: v.filter.to_string(),
229
+ consumer,
230
+ }
231
+ } else {
232
+ Logger::Console {
233
+ filter: v.filter.to_string(),
234
+ }
235
+ });
236
+ }
237
+ build.build()?
238
+ } else {
239
+ CoreTelemetryOptions::default()
240
+ };
241
+
242
+ // Build core runtime
243
+ let mut core = CoreRuntime::new(telemetry_options, TokioRuntimeBuilder::default())?;
244
+
245
+ // We late-bind the metrics after core runtime is created since it needs
246
+ // the Tokio handle
247
+ if let Some(v) = unsafe { options.telemetry.as_ref() }
248
+ && let Some(v) = unsafe { v.metrics.as_ref() }
249
+ {
250
+ let _guard = core.tokio_handle().enter();
251
+ core.telemetry_mut()
252
+ .attach_late_init_metrics(create_meter(v, custom_meter)?);
253
+ }
254
+
255
+ // Create runtime
256
+ let runtime = Runtime {
257
+ core: Arc::new(core),
258
+ log_forwarder,
259
+ };
260
+
261
+ // Set log forwarder to active. We do this later so logs don't get
262
+ // inadvertently sent if this errors above.
263
+ if let Some(log_forwarder) = runtime.log_forwarder.as_ref() {
264
+ log_forwarder.active.store(true, Ordering::Release);
265
+ }
266
+
267
+ Ok(runtime)
268
+ }
269
+
270
+ fn borrow_buf(&mut self) -> Vec<u8> {
271
+ // We currently do not use a thread-safe byte pool, but if wanted, it
272
+ // can be added here
273
+ Vec::new()
274
+ }
275
+
276
+ fn return_buf(&mut self, _vec: Vec<u8>) {
277
+ // We currently do not use a thread-safe byte pool, but if wanted, it
278
+ // can be added here
279
+ }
280
+
281
+ pub fn alloc_utf8(&mut self, v: &str) -> ByteArray {
282
+ let mut buf = self.borrow_buf();
283
+ buf.clear();
284
+ buf.extend_from_slice(v.as_bytes());
285
+ ByteArray::from_vec(buf)
286
+ }
287
+ }
288
+
289
+ impl Drop for Runtime {
290
+ fn drop(&mut self) {
291
+ if let Some(log_forwarder) = self.log_forwarder.as_ref() {
292
+ // Need strong guarantees to ensure the callback is not called again
293
+ // after this drop completes
294
+ log_forwarder.active.store(false, Ordering::Release);
295
+ }
296
+ }
297
+ }
298
+
299
+ struct LogForwarder {
300
+ callback: unsafe extern "C" fn(level: ForwardedLogLevel, log: *const ForwardedLog),
301
+ active: AtomicBool,
302
+ }
303
+
304
+ impl CoreLogConsumer for LogForwarder {
305
+ fn on_log(&self, log: CoreLog) {
306
+ // Check whether active w/ strong consistency
307
+ if self.active.load(Ordering::Acquire) {
308
+ let level = match log.level {
309
+ Level::TRACE => ForwardedLogLevel::Trace,
310
+ Level::DEBUG => ForwardedLogLevel::Debug,
311
+ Level::INFO => ForwardedLogLevel::Info,
312
+ Level::WARN => ForwardedLogLevel::Warn,
313
+ Level::ERROR => ForwardedLogLevel::Error,
314
+ };
315
+ // Create log here to live the life of the callback
316
+ let log = ForwardedLog {
317
+ core: log,
318
+ fields_json: Arc::new(Mutex::new(None)),
319
+ };
320
+ unsafe { (self.callback)(level, &log) };
321
+ }
322
+ }
323
+ }
324
+
325
+ impl fmt::Debug for LogForwarder {
326
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
327
+ f.write_str("<log forwarder>")
328
+ }
329
+ }
330
+
331
+ #[unsafe(no_mangle)]
332
+ pub extern "C" fn temporal_core_forwarded_log_target(log: *const ForwardedLog) -> ByteArrayRef {
333
+ let log = unsafe { &*log };
334
+ log.core.target.as_str().into()
335
+ }
336
+
337
+ #[unsafe(no_mangle)]
338
+ pub extern "C" fn temporal_core_forwarded_log_message(log: *const ForwardedLog) -> ByteArrayRef {
339
+ let log = unsafe { &*log };
340
+ log.core.message.as_str().into()
341
+ }
342
+
343
+ #[unsafe(no_mangle)]
344
+ pub extern "C" fn temporal_core_forwarded_log_timestamp_millis(log: *const ForwardedLog) -> u64 {
345
+ let log = unsafe { &*log };
346
+ log.core
347
+ .timestamp
348
+ .duration_since(UNIX_EPOCH)
349
+ .unwrap()
350
+ .as_millis()
351
+ .try_into()
352
+ .unwrap()
353
+ }
354
+
355
+ #[unsafe(no_mangle)]
356
+ pub extern "C" fn temporal_core_forwarded_log_fields_json(
357
+ log: *const ForwardedLog,
358
+ ) -> ByteArrayRef {
359
+ let log = unsafe { &*log };
360
+ // If not set, we convert to JSON under lock then set
361
+ let fields_json = log.fields_json.clone();
362
+ let mut fields_json = fields_json.lock().unwrap();
363
+ fields_json
364
+ .get_or_insert_with(|| json!(&log.core.fields).to_string())
365
+ .as_str()
366
+ .into()
367
+ }
368
+
369
+ fn create_meter(
370
+ options: &MetricsOptions,
371
+ custom_meter: Option<CustomMetricMeterRef>,
372
+ ) -> anyhow::Result<Arc<dyn CoreMeter>> {
373
+ // OTel, Prom, or custom
374
+ if let Some(otel_options) = unsafe { options.opentelemetry.as_ref() } {
375
+ if !options.prometheus.is_null() || custom_meter.is_some() {
376
+ return Err(anyhow::anyhow!(
377
+ "Cannot have OpenTelemetry and Prometheus metrics or custom meter"
378
+ ));
379
+ }
380
+ // Build OTel exporter
381
+ let mut build = OtelCollectorOptionsBuilder::default();
382
+ build
383
+ .url(Url::parse(otel_options.url.to_str())?)
384
+ .headers(otel_options.headers.to_string_map_on_newlines())
385
+ .metric_temporality(match otel_options.metric_temporality {
386
+ OpenTelemetryMetricTemporality::Cumulative => MetricTemporality::Cumulative,
387
+ OpenTelemetryMetricTemporality::Delta => MetricTemporality::Delta,
388
+ })
389
+ .global_tags(options.global_tags.to_string_map_on_newlines())
390
+ .use_seconds_for_durations(otel_options.durations_as_seconds)
391
+ .histogram_bucket_overrides(HistogramBucketOverrides {
392
+ overrides: parse_histogram_bucket_overrides(
393
+ &otel_options.histogram_bucket_overrides,
394
+ )?,
395
+ });
396
+ if otel_options.metric_periodicity_millis > 0 {
397
+ build.metric_periodicity(Duration::from_millis(
398
+ otel_options.metric_periodicity_millis.into(),
399
+ ));
400
+ }
401
+ Ok(Arc::new(build_otlp_metric_exporter(build.build()?)?))
402
+ } else if let Some(prom_options) = unsafe { options.prometheus.as_ref() } {
403
+ if custom_meter.is_some() {
404
+ return Err(anyhow::anyhow!(
405
+ "Cannot have Prometheus metrics and custom meter"
406
+ ));
407
+ }
408
+ // Start prom exporter
409
+ let mut build = PrometheusExporterOptionsBuilder::default();
410
+ build
411
+ .socket_addr(SocketAddr::from_str(prom_options.bind_address.to_str())?)
412
+ .global_tags(options.global_tags.to_string_map_on_newlines())
413
+ .counters_total_suffix(prom_options.counters_total_suffix)
414
+ .unit_suffix(prom_options.unit_suffix)
415
+ .use_seconds_for_durations(prom_options.durations_as_seconds)
416
+ .histogram_bucket_overrides(HistogramBucketOverrides {
417
+ overrides: parse_histogram_bucket_overrides(
418
+ &prom_options.histogram_bucket_overrides,
419
+ )?,
420
+ });
421
+ Ok(start_prometheus_metric_exporter(build.build()?)?.meter)
422
+ } else if let Some(custom_meter) = custom_meter {
423
+ Ok(Arc::new(custom_meter))
424
+ } else {
425
+ Err(anyhow::anyhow!(
426
+ "Either OpenTelemetry config, Prometheus config, or custom meter must be provided"
427
+ ))
428
+ }
429
+ }
430
+
431
+ fn parse_histogram_bucket_overrides(
432
+ raw: &MetadataRef,
433
+ ) -> anyhow::Result<HashMap<String, Vec<f64>>> {
434
+ raw.to_string_map_on_newlines()
435
+ .into_iter()
436
+ .map(|(k, v)| {
437
+ let vals: anyhow::Result<Vec<f64>> = v
438
+ .split(',')
439
+ .map(str::parse::<f64>)
440
+ .collect::<Result<_, _>>() // Result<Vec<f64>, ParseFloatError>
441
+ .map_err(Into::into);
442
+ vals.map(|vals| (k, vals))
443
+ })
444
+ .collect()
445
+ }