@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.
- package/Cargo.lock +64 -119
- package/Cargo.toml +1 -1
- package/index.js +3 -2
- package/package.json +3 -3
- package/releases/aarch64-apple-darwin/index.node +0 -0
- package/releases/aarch64-unknown-linux-gnu/index.node +0 -0
- package/releases/x86_64-apple-darwin/index.node +0 -0
- package/releases/x86_64-pc-windows-msvc/index.node +0 -0
- package/releases/x86_64-unknown-linux-gnu/index.node +0 -0
- package/sdk-core/.cargo/config.toml +1 -2
- package/sdk-core/.github/workflows/per-pr.yml +2 -0
- package/sdk-core/AGENTS.md +7 -0
- package/sdk-core/Cargo.toml +9 -5
- package/sdk-core/README.md +6 -5
- package/sdk-core/client/Cargo.toml +3 -2
- package/sdk-core/client/src/lib.rs +17 -8
- package/sdk-core/client/src/metrics.rs +57 -23
- package/sdk-core/client/src/raw.rs +33 -15
- package/sdk-core/core/Cargo.toml +11 -9
- package/sdk-core/core/benches/workflow_replay.rs +114 -15
- package/sdk-core/core/src/core_tests/activity_tasks.rs +18 -18
- package/sdk-core/core/src/core_tests/child_workflows.rs +4 -4
- package/sdk-core/core/src/core_tests/determinism.rs +6 -6
- package/sdk-core/core/src/core_tests/local_activities.rs +20 -20
- package/sdk-core/core/src/core_tests/mod.rs +40 -5
- package/sdk-core/core/src/core_tests/queries.rs +25 -16
- package/sdk-core/core/src/core_tests/replay_flag.rs +3 -3
- package/sdk-core/core/src/core_tests/updates.rs +3 -3
- package/sdk-core/core/src/core_tests/workers.rs +9 -7
- package/sdk-core/core/src/core_tests/workflow_tasks.rs +40 -42
- package/sdk-core/core/src/ephemeral_server/mod.rs +1 -19
- package/sdk-core/core/src/lib.rs +10 -1
- package/sdk-core/core/src/pollers/poll_buffer.rs +2 -2
- package/sdk-core/core/src/replay/mod.rs +3 -3
- package/sdk-core/core/src/telemetry/metrics.rs +306 -152
- package/sdk-core/core/src/telemetry/mod.rs +11 -4
- package/sdk-core/core/src/telemetry/otel.rs +134 -131
- package/sdk-core/core/src/telemetry/prometheus_meter.rs +885 -0
- package/sdk-core/core/src/telemetry/prometheus_server.rs +48 -28
- package/sdk-core/core/src/test_help/mod.rs +27 -12
- package/sdk-core/core/src/worker/activities/activity_heartbeat_manager.rs +7 -7
- package/sdk-core/core/src/worker/activities.rs +4 -4
- package/sdk-core/core/src/worker/client/mocks.rs +10 -3
- package/sdk-core/core/src/worker/client.rs +68 -5
- package/sdk-core/core/src/worker/heartbeat.rs +229 -0
- package/sdk-core/core/src/worker/mod.rs +35 -14
- package/sdk-core/core/src/worker/tuner/resource_based.rs +4 -4
- package/sdk-core/core/src/worker/workflow/history_update.rs +71 -19
- package/sdk-core/core/src/worker/workflow/machines/cancel_external_state_machine.rs +1 -2
- package/sdk-core/core/src/worker/workflow/machines/child_workflow_state_machine.rs +1 -1
- package/sdk-core/core/src/worker/workflow/machines/nexus_operation_state_machine.rs +31 -48
- package/sdk-core/core/src/worker/workflow/machines/signal_external_state_machine.rs +1 -2
- package/sdk-core/core/src/worker/workflow/machines/upsert_search_attributes_state_machine.rs +3 -3
- package/sdk-core/core/src/worker/workflow/machines/workflow_machines.rs +4 -1
- package/sdk-core/core/src/worker/workflow/managed_run.rs +1 -1
- package/sdk-core/core/src/worker/workflow/mod.rs +15 -15
- package/sdk-core/core-api/Cargo.toml +2 -2
- package/sdk-core/core-api/src/envconfig.rs +204 -99
- package/sdk-core/core-api/src/lib.rs +9 -0
- package/sdk-core/core-api/src/telemetry/metrics.rs +548 -100
- package/sdk-core/core-api/src/worker.rs +11 -5
- package/sdk-core/core-c-bridge/Cargo.toml +49 -0
- package/sdk-core/core-c-bridge/build.rs +26 -0
- package/sdk-core/core-c-bridge/include/temporal-sdk-core-c-bridge.h +817 -0
- package/sdk-core/core-c-bridge/src/client.rs +679 -0
- package/sdk-core/core-c-bridge/src/lib.rs +245 -0
- package/sdk-core/core-c-bridge/src/metric.rs +682 -0
- package/sdk-core/core-c-bridge/src/random.rs +61 -0
- package/sdk-core/core-c-bridge/src/runtime.rs +445 -0
- package/sdk-core/core-c-bridge/src/testing.rs +282 -0
- package/sdk-core/core-c-bridge/src/tests/context.rs +644 -0
- package/sdk-core/core-c-bridge/src/tests/mod.rs +178 -0
- package/sdk-core/core-c-bridge/src/tests/utils.rs +108 -0
- package/sdk-core/core-c-bridge/src/worker.rs +1069 -0
- package/sdk-core/etc/deps.svg +64 -64
- package/sdk-core/sdk/src/activity_context.rs +6 -4
- package/sdk-core/sdk/src/lib.rs +49 -27
- package/sdk-core/sdk/src/workflow_future.rs +18 -25
- package/sdk-core/sdk-core-protos/protos/api_upstream/README.md +4 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/buf.yaml +0 -2
- package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/openapiv2.json +630 -83
- package/sdk-core/sdk-core-protos/protos/api_upstream/openapi/openapiv3.yaml +632 -78
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/batch/v1/message.proto +4 -4
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/command/v1/message.proto +6 -4
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/common/v1/message.proto +2 -2
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/deployment/v1/message.proto +32 -2
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/common.proto +10 -1
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/deployment.proto +26 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/failed_cause.proto +2 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/enums/v1/reset.proto +4 -4
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/failure/v1/message.proto +2 -2
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/history/v1/message.proto +47 -31
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/nexus/v1/message.proto +4 -4
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/schedule/v1/message.proto +7 -1
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/worker/v1/message.proto +134 -0
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflow/v1/message.proto +14 -11
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflowservice/v1/request_response.proto +148 -37
- package/sdk-core/sdk-core-protos/protos/api_upstream/temporal/api/workflowservice/v1/service.proto +21 -0
- package/sdk-core/sdk-core-protos/protos/local/temporal/sdk/core/workflow_activation/workflow_activation.proto +4 -4
- package/sdk-core/sdk-core-protos/src/history_builder.rs +9 -5
- package/sdk-core/sdk-core-protos/src/lib.rs +96 -6
- package/sdk-core/test-utils/src/lib.rs +11 -3
- package/sdk-core/tests/cloud_tests.rs +3 -3
- package/sdk-core/tests/heavy_tests.rs +11 -3
- package/sdk-core/tests/integ_tests/client_tests.rs +12 -13
- package/sdk-core/tests/integ_tests/ephemeral_server_tests.rs +1 -1
- package/sdk-core/tests/integ_tests/metrics_tests.rs +188 -83
- package/sdk-core/tests/integ_tests/polling_tests.rs +1 -1
- package/sdk-core/tests/integ_tests/queries_tests.rs +56 -40
- package/sdk-core/tests/integ_tests/update_tests.rs +2 -7
- package/sdk-core/tests/integ_tests/worker_tests.rs +3 -4
- package/sdk-core/tests/integ_tests/worker_versioning_tests.rs +3 -7
- package/sdk-core/tests/integ_tests/workflow_tests/local_activities.rs +3 -5
- package/sdk-core/tests/integ_tests/workflow_tests/nexus.rs +24 -17
- package/src/client.rs +6 -0
- 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
|
+
}
|