@cratis/chronicle 6.33.0 → 6.35.0
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/ChronicleClient.ts +43 -35
- package/ChronicleOptions.ts +27 -1
- package/EventStore.ts +22 -12
- package/Metrics.ts +70 -96
- package/Tracing.ts +4 -2
- package/WellKnownTelemetryNames.ts +67 -0
- package/artifacts/validateArtifactSchemas.spec.ts +1 -1
- package/artifacts/withActivatedArtifact.ts +7 -5
- package/connection/ChronicleConnection.ts +18 -6
- package/connection/CompatibilityPreflight.ts +2 -1
- package/connection/KernelKeepAlive.ts +13 -7
- package/connection/TokenProvider.ts +3 -1
- package/connection/TraceContextMiddleware.ts +30 -0
- package/connection/for_ChronicleConnection/when_creating_clients/with_correlated_multi_host_callers.spec.ts +73 -0
- package/connection/for_OAuthTokenProvider/when_acquiring_tokens/with_http_instrumentation.spec.ts +102 -0
- package/connection/for_TraceContextMiddleware/when_calling/with_active_context.spec.ts +235 -0
- package/connection/for_TraceContextMiddleware/when_calling/with_grpc_instrumentation.spec.ts +102 -0
- package/correlation/CorrelationIdManager.ts +10 -0
- package/dist/ChronicleClient.d.ts.map +1 -1
- package/dist/ChronicleClient.js +45 -35
- package/dist/ChronicleClient.js.map +1 -1
- package/dist/ChronicleOptions.d.ts +8 -0
- package/dist/ChronicleOptions.d.ts.map +1 -1
- package/dist/ChronicleOptions.js +19 -1
- package/dist/ChronicleOptions.js.map +1 -1
- package/dist/EventStore.d.ts +3 -1
- package/dist/EventStore.d.ts.map +1 -1
- package/dist/EventStore.js +22 -12
- package/dist/EventStore.js.map +1 -1
- package/dist/Metrics.d.ts +23 -64
- package/dist/Metrics.d.ts.map +1 -1
- package/dist/Metrics.js +62 -92
- package/dist/Metrics.js.map +1 -1
- package/dist/Tracing.d.ts +1 -1
- package/dist/Tracing.d.ts.map +1 -1
- package/dist/Tracing.js +4 -2
- package/dist/Tracing.js.map +1 -1
- package/dist/WellKnownTelemetryNames.d.ts +65 -0
- package/dist/WellKnownTelemetryNames.d.ts.map +1 -0
- package/dist/WellKnownTelemetryNames.js +67 -0
- package/dist/WellKnownTelemetryNames.js.map +1 -0
- package/dist/artifacts/withActivatedArtifact.d.ts +2 -1
- package/dist/artifacts/withActivatedArtifact.d.ts.map +1 -1
- package/dist/artifacts/withActivatedArtifact.js +5 -4
- package/dist/artifacts/withActivatedArtifact.js.map +1 -1
- package/dist/connection/ChronicleConnection.d.ts +5 -0
- package/dist/connection/ChronicleConnection.d.ts.map +1 -1
- package/dist/connection/ChronicleConnection.js +13 -6
- package/dist/connection/ChronicleConnection.js.map +1 -1
- package/dist/connection/CompatibilityPreflight.d.ts.map +1 -1
- package/dist/connection/CompatibilityPreflight.js +2 -1
- package/dist/connection/CompatibilityPreflight.js.map +1 -1
- package/dist/connection/KernelKeepAlive.d.ts +3 -1
- package/dist/connection/KernelKeepAlive.d.ts.map +1 -1
- package/dist/connection/KernelKeepAlive.js +10 -7
- package/dist/connection/KernelKeepAlive.js.map +1 -1
- package/dist/connection/TokenProvider.d.ts.map +1 -1
- package/dist/connection/TokenProvider.js +3 -1
- package/dist/connection/TokenProvider.js.map +1 -1
- package/dist/connection/TraceContextMiddleware.d.ts +4 -0
- package/dist/connection/TraceContextMiddleware.d.ts.map +1 -0
- package/dist/connection/TraceContextMiddleware.js +30 -0
- package/dist/connection/TraceContextMiddleware.js.map +1 -0
- package/dist/correlation/CorrelationIdManager.d.ts +4 -0
- package/dist/correlation/CorrelationIdManager.d.ts.map +1 -1
- package/dist/correlation/CorrelationIdManager.js +8 -0
- package/dist/correlation/CorrelationIdManager.js.map +1 -1
- package/dist/eventSequences/EventLog.d.ts +2 -1
- package/dist/eventSequences/EventLog.d.ts.map +1 -1
- package/dist/eventSequences/EventLog.js +2 -2
- package/dist/eventSequences/EventLog.js.map +1 -1
- package/dist/eventSequences/EventSequence.d.ts +4 -1
- package/dist/eventSequences/EventSequence.d.ts.map +1 -1
- package/dist/eventSequences/EventSequence.js +63 -80
- package/dist/eventSequences/EventSequence.js.map +1 -1
- package/dist/eventStoreSubscriptions/EventStoreSubscriptions.d.ts.map +1 -1
- package/dist/eventStoreSubscriptions/EventStoreSubscriptions.js +3 -4
- package/dist/eventStoreSubscriptions/EventStoreSubscriptions.js.map +1 -1
- package/dist/events/handles.d.ts +12 -0
- package/dist/events/handles.d.ts.map +1 -0
- package/dist/events/handles.js +33 -0
- package/dist/events/handles.js.map +1 -0
- package/dist/events/index.d.ts +1 -0
- package/dist/events/index.d.ts.map +1 -1
- package/dist/events/index.js +1 -0
- package/dist/events/index.js.map +1 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/logging/ChronicleLogEntry.d.ts +11 -0
- package/dist/logging/ChronicleLogEntry.d.ts.map +1 -0
- package/dist/logging/ChronicleLogEntry.js +4 -0
- package/dist/logging/ChronicleLogEntry.js.map +1 -0
- package/dist/logging/ChronicleLogLevel.d.ts +9 -0
- package/dist/logging/ChronicleLogLevel.d.ts.map +1 -0
- package/dist/logging/ChronicleLogLevel.js +12 -0
- package/dist/logging/ChronicleLogLevel.js.map +1 -0
- package/dist/logging/DiagChronicleLogger.d.ts +7 -0
- package/dist/logging/DiagChronicleLogger.d.ts.map +1 -0
- package/dist/logging/DiagChronicleLogger.js +10 -0
- package/dist/logging/DiagChronicleLogger.js.map +1 -0
- package/dist/logging/IChronicleLogger.d.ts +7 -0
- package/dist/logging/IChronicleLogger.d.ts.map +1 -0
- package/dist/logging/IChronicleLogger.js +4 -0
- package/dist/logging/IChronicleLogger.js.map +1 -0
- package/dist/logging/createLogger.d.ts +10 -0
- package/dist/logging/createLogger.d.ts.map +1 -0
- package/dist/logging/createLogger.js +55 -0
- package/dist/logging/createLogger.js.map +1 -0
- package/dist/observation/EventHandler.d.ts +7 -0
- package/dist/observation/EventHandler.d.ts.map +1 -0
- package/dist/observation/EventHandler.js +4 -0
- package/dist/observation/EventHandler.js.map +1 -0
- package/dist/observation/createHandlerInstanceValidator.d.ts +4 -0
- package/dist/observation/createHandlerInstanceValidator.d.ts.map +1 -0
- package/dist/observation/createHandlerInstanceValidator.js +40 -0
- package/dist/observation/createHandlerInstanceValidator.js.map +1 -0
- package/dist/observation/getEventHandlers.d.ts +5 -0
- package/dist/observation/getEventHandlers.d.ts.map +1 -0
- package/dist/observation/getEventHandlers.js +40 -0
- package/dist/observation/getEventHandlers.js.map +1 -0
- package/dist/observation/getInstanceMethods.d.ts +4 -0
- package/dist/observation/getInstanceMethods.d.ts.map +1 -0
- package/dist/observation/getInstanceMethods.js +29 -0
- package/dist/observation/getInstanceMethods.js.map +1 -0
- package/dist/projections/Projections.d.ts.map +1 -1
- package/dist/projections/Projections.js +4 -3
- package/dist/projections/Projections.js.map +1 -1
- package/dist/reactors/ReactorDispatcher.d.ts.map +1 -1
- package/dist/reactors/ReactorDispatcher.js +27 -32
- package/dist/reactors/ReactorDispatcher.js.map +1 -1
- package/dist/reactors/Reactors.d.ts +1 -0
- package/dist/reactors/Reactors.d.ts.map +1 -1
- package/dist/reactors/Reactors.js +49 -34
- package/dist/reactors/Reactors.js.map +1 -1
- package/dist/reactors/index.d.ts +1 -0
- package/dist/reactors/index.d.ts.map +1 -1
- package/dist/reactors/index.js +1 -0
- package/dist/reactors/index.js.map +1 -1
- package/dist/reducers/ReducerEventDispatcher.d.ts +1 -0
- package/dist/reducers/ReducerEventDispatcher.d.ts.map +1 -1
- package/dist/reducers/ReducerEventDispatcher.js +5 -17
- package/dist/reducers/ReducerEventDispatcher.js.map +1 -1
- package/dist/reducers/ReducerEventHandler.d.ts +3 -6
- package/dist/reducers/ReducerEventHandler.d.ts.map +1 -1
- package/dist/reducers/Reducers.d.ts +1 -0
- package/dist/reducers/Reducers.d.ts.map +1 -1
- package/dist/reducers/Reducers.js +47 -32
- package/dist/reducers/Reducers.js.map +1 -1
- package/dist/reducers/index.d.ts +1 -0
- package/dist/reducers/index.d.ts.map +1 -1
- package/dist/reducers/index.js +1 -0
- package/dist/reducers/index.js.map +1 -1
- package/dist/seeding/EventSeeding.d.ts.map +1 -1
- package/dist/seeding/EventSeeding.js +4 -3
- package/dist/seeding/EventSeeding.js.map +1 -1
- package/dist/telemetry/ChronicleTelemetryOptions.d.ts +11 -0
- package/dist/telemetry/ChronicleTelemetryOptions.d.ts.map +1 -0
- package/dist/telemetry/ChronicleTelemetryOptions.js +4 -0
- package/dist/telemetry/ChronicleTelemetryOptions.js.map +1 -0
- package/dist/telemetry/observeOperation.d.ts +6 -0
- package/dist/telemetry/observeOperation.d.ts.map +1 -0
- package/dist/telemetry/observeOperation.js +23 -0
- package/dist/telemetry/observeOperation.js.map +1 -0
- package/dist/telemetry/runInBackgroundContext.d.ts +3 -0
- package/dist/telemetry/runInBackgroundContext.d.ts.map +1 -0
- package/dist/telemetry/runInBackgroundContext.js +9 -0
- package/dist/telemetry/runInBackgroundContext.js.map +1 -0
- package/dist/telemetry/spanAttributes.d.ts +14 -0
- package/dist/telemetry/spanAttributes.d.ts.map +1 -0
- package/dist/telemetry/spanAttributes.js +47 -0
- package/dist/telemetry/spanAttributes.js.map +1 -0
- package/dist/testing/ReactorScenario.d.ts +1 -0
- package/dist/testing/ReactorScenario.d.ts.map +1 -1
- package/dist/testing/ReactorScenario.js +9 -1
- package/dist/testing/ReactorScenario.js.map +1 -1
- package/dist/testing/ReducerReadModelProcessor.d.ts.map +1 -1
- package/dist/testing/ReducerReadModelProcessor.js +1 -0
- package/dist/testing/ReducerReadModelProcessor.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/eventSequences/EventLog.ts +4 -2
- package/eventSequences/EventSequence.ts +64 -81
- package/eventStoreSubscriptions/EventStoreSubscriptions.ts +5 -5
- package/events/for_handles/when_decorating_a_method.legacy.spec.ts +91 -0
- package/events/for_handles/when_decorating_a_method.standard.spec.ts +102 -0
- package/events/handles.ts +37 -0
- package/events/index.ts +1 -0
- package/for_ChronicleClient/when_registering_artifacts/with_invalid_handler_mappings.spec.ts +142 -0
- package/for_ChronicleClient/when_starting_background_work/with_a_correlated_caller.spec.ts +150 -0
- package/for_ChronicleOptions/when_configuring_telemetry/with_event_source_identifiers.spec.ts +44 -0
- package/index.ts +7 -1
- package/logging/ChronicleLogEntry.ts +14 -0
- package/logging/ChronicleLogLevel.ts +11 -0
- package/logging/DiagChronicleLogger.ts +13 -0
- package/logging/IChronicleLogger.ts +10 -0
- package/logging/createLogger.ts +50 -0
- package/logging/for_ChronicleLogger/when_logging/with_client_owned_sinks.spec.ts +96 -0
- package/observation/EventHandler.ts +9 -0
- package/observation/createHandlerInstanceValidator.ts +42 -0
- package/observation/for_getEventHandlers/when_discovering_handlers.spec.ts +137 -0
- package/observation/for_getEventHandlers/when_reobserving_explicit_handlers.spec.ts +73 -0
- package/observation/getEventHandlers.ts +43 -0
- package/observation/getInstanceMethods.ts +29 -0
- package/package.json +8 -2
- package/projections/Projections.ts +4 -3
- package/reactors/ReactorDispatcher.ts +26 -30
- package/reactors/Reactors.ts +55 -37
- package/reactors/decorators.standard.spec.ts +8 -0
- package/reactors/for_ReactorDispatcher/when_selecting_explicit_handlers.spec.ts +64 -0
- package/reactors/for_Reactors/when_activating_a_field_override.spec.ts +62 -0
- package/reactors/for_Reactors/when_delivering/with_activation.spec.ts +14 -14
- package/reactors/for_Reactors/when_delivering_to_instance_handlers.spec.ts +108 -0
- package/reactors/for_Reactors/when_observing_explicit_handlers.legacy.spec.ts +77 -0
- package/reactors/for_Reactors/when_registering_explicit_handlers.spec.ts +53 -0
- package/reactors/index.ts +1 -0
- package/reducers/ReducerEventDispatcher.ts +5 -16
- package/reducers/ReducerEventHandler.ts +4 -6
- package/reducers/Reducers.ts +50 -35
- package/reducers/for_ReducerEventDispatcher/when_invoking_an_explicit_handler.spec.ts +51 -0
- package/reducers/for_ReducerEventDispatcher/when_invoking_instance_handlers.spec.ts +69 -0
- package/reducers/for_Reducers/when_activating_a_field_override.spec.ts +63 -0
- package/reducers/for_Reducers/when_observing_explicit_handlers.legacy.spec.ts +73 -0
- package/reducers/for_Reducers/when_registering_explicit_handlers.spec.ts +57 -0
- package/reducers/index.ts +1 -0
- package/seeding/EventSeeding.ts +6 -4
- package/telemetry/ChronicleTelemetryOptions.ts +8 -0
- package/telemetry/for_ChronicleTelemetry/given/a_telemetry_session.fixture.ts +36 -0
- package/telemetry/for_ChronicleTelemetry/given/an_event_sequence.fixture.ts +29 -0
- package/telemetry/for_ChronicleTelemetry/when_appending/with_shared_and_legacy_attributes.spec.ts +58 -0
- package/telemetry/for_ChronicleTelemetry/when_appending/without_an_sdk.spec.ts +15 -0
- package/telemetry/for_ChronicleTelemetry/when_documenting/with_public_names.spec.ts +15 -0
- package/telemetry/for_ChronicleTelemetry/when_recording_failures/with_sensitive_exception_details.spec.ts +34 -0
- package/telemetry/for_ChronicleTelemetry/when_recording_identifiers/with_per_client_privacy.spec.ts +92 -0
- package/telemetry/for_ChronicleTelemetry/when_recording_metrics/with_legacy_overlap.spec.ts +40 -0
- package/telemetry/for_ChronicleTelemetry/when_recording_sequence_numbers/with_integer_precision.spec.ts +23 -0
- package/telemetry/observeOperation.ts +25 -0
- package/telemetry/runInBackgroundContext.ts +10 -0
- package/telemetry/spanAttributes.ts +49 -0
- package/testing/ReactorScenario.ts +9 -1
- package/testing/ReducerReadModelProcessor.ts +1 -0
- package/testing/for_ReactorScenario/when_delivering_to_an_explicit_handler.spec.ts +100 -0
- package/testing/for_ReducerReadModelProcessor/when_an_instance_field_hides_a_handler.spec.ts +29 -0
package/ChronicleClient.ts
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
3
3
|
|
|
4
4
|
import * as os from 'os';
|
|
5
|
-
import {
|
|
5
|
+
import { createLogger } from './logging/createLogger.js';
|
|
6
|
+
import { setTelemetryAttribute, recordSafeException } from './telemetry/spanAttributes.js';
|
|
7
|
+
import { WellKnownTelemetryNames } from './WellKnownTelemetryNames.js';
|
|
6
8
|
import { SpanStatusCode } from '@opentelemetry/api';
|
|
7
9
|
import { ChronicleOptions } from './ChronicleOptions.js';
|
|
8
10
|
import { ChronicleConnection } from './connection/index.js';
|
|
@@ -19,7 +21,8 @@ import { EventStoreNamespaceName } from './EventStoreNamespaceName.js';
|
|
|
19
21
|
import { IChronicleClient } from './IChronicleClient.js';
|
|
20
22
|
import { IEventStore } from './IEventStore.js';
|
|
21
23
|
import { ChronicleMetrics } from './Metrics.js';
|
|
22
|
-
import {
|
|
24
|
+
import { observeOperation } from './telemetry/observeOperation.js';
|
|
25
|
+
import { runInBackgroundContext } from './telemetry/runInBackgroundContext.js';
|
|
23
26
|
import { TypeDiscoverer } from './types/index.js';
|
|
24
27
|
import { takeUnregisteredModelBoundMappings } from './types/modelBoundPropertyMetadata.js';
|
|
25
28
|
import { reachableReadModelTypes } from './readModels/rootReadModelTypes.js';
|
|
@@ -45,9 +48,7 @@ export class ChronicleClient implements IChronicleClient {
|
|
|
45
48
|
private readonly _stores: Map<string, EventStore> = new Map();
|
|
46
49
|
private readonly _lifecycle = new ConnectionLifecycle();
|
|
47
50
|
|
|
48
|
-
private readonly _logger
|
|
49
|
-
namespace: '@cratis/chronicle/ChronicleClient'
|
|
50
|
-
});
|
|
51
|
+
private readonly _logger: ReturnType<typeof createLogger>;
|
|
51
52
|
|
|
52
53
|
private _watchdogHandle?: ReturnType<typeof setInterval>;
|
|
53
54
|
private _connectOperation?: Promise<void>;
|
|
@@ -64,6 +65,7 @@ export class ChronicleClient implements IChronicleClient {
|
|
|
64
65
|
* @param options - The options to configure the client, including the connection string.
|
|
65
66
|
*/
|
|
66
67
|
constructor(readonly options: ChronicleOptions) {
|
|
68
|
+
this._logger = createLogger('@cratis/chronicle/ChronicleClient', options.logger);
|
|
67
69
|
// When TLS is disabled, pass pre-built insecure credentials directly.
|
|
68
70
|
// @cratis/chronicle.contracts ≤15.24.3 always composes call credentials with
|
|
69
71
|
// channel credentials, which gRPC forbids for insecure channels. Passing
|
|
@@ -72,7 +74,7 @@ export class ChronicleClient implements IChronicleClient {
|
|
|
72
74
|
const connectionOptions = options.connectionString.disableTls
|
|
73
75
|
? { connectionString: options.connectionString, credentials: options.connectionString.createCredentials() }
|
|
74
76
|
: { connectionString: options.connectionString };
|
|
75
|
-
this._connection = new ChronicleConnection(connectionOptions);
|
|
77
|
+
this._connection = new ChronicleConnection({ ...connectionOptions, logger: options.logger });
|
|
76
78
|
|
|
77
79
|
this._logger.info('Created Chronicle client', {
|
|
78
80
|
serverAddress: `${options.connectionString.serverAddress.host}:${options.connectionString.serverAddress.port}`,
|
|
@@ -80,9 +82,11 @@ export class ChronicleClient implements IChronicleClient {
|
|
|
80
82
|
});
|
|
81
83
|
|
|
82
84
|
if (options.discoveryPatterns.length > 0) {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
this.
|
|
85
|
+
runInBackgroundContext(() => {
|
|
86
|
+
this._discoveryOperation = TypeDiscoverer.default.discover(options.discoveryPatterns);
|
|
87
|
+
this._discoveryOperation.catch(error => {
|
|
88
|
+
this._logger.error('Artifact file discovery failed', { error });
|
|
89
|
+
});
|
|
86
90
|
});
|
|
87
91
|
}
|
|
88
92
|
|
|
@@ -120,9 +124,9 @@ export class ChronicleClient implements IChronicleClient {
|
|
|
120
124
|
? new EventStoreNamespaceName(namespace)
|
|
121
125
|
: namespace;
|
|
122
126
|
|
|
123
|
-
return
|
|
124
|
-
span
|
|
125
|
-
span
|
|
127
|
+
return observeOperation(WellKnownTelemetryNames.spans.getEventStore, async span => {
|
|
128
|
+
setTelemetryAttribute(span, 'eventStore', storeName.value);
|
|
129
|
+
setTelemetryAttribute(span, 'namespace', namespaceName.value);
|
|
126
130
|
try {
|
|
127
131
|
const store = await this.withReconnect('get_event_store', async () => {
|
|
128
132
|
await this.ensureConnected();
|
|
@@ -142,11 +146,17 @@ export class ChronicleClient implements IChronicleClient {
|
|
|
142
146
|
});
|
|
143
147
|
ensureCommandSuccess('ensure event store', await this._connection.eventStores.ensureEventStore({ Name: storeName.value }));
|
|
144
148
|
|
|
145
|
-
const created = new EventStore(storeName, namespaceName, this._connection, this._lifecycle, this.options.defaultSinkTypeId, this.options.clientArtifactsProvider, this.options.reactorResultHandler, this.options.artifactActivator, this.options.readModelNamingPolicy);
|
|
149
|
+
const created = new EventStore(storeName, namespaceName, this._connection, this._lifecycle, this.options.defaultSinkTypeId, this.options.clientArtifactsProvider, this.options.reactorResultHandler, this.options.artifactActivator, this.options.readModelNamingPolicy, this.options.telemetry);
|
|
146
150
|
this._stores.set(key, created);
|
|
147
151
|
|
|
148
|
-
|
|
149
|
-
|
|
152
|
+
try {
|
|
153
|
+
await this.registerArtifactsForStore(created, 'new-store');
|
|
154
|
+
return created;
|
|
155
|
+
} catch (error) {
|
|
156
|
+
if (this._stores.get(key) === created) this._stores.delete(key);
|
|
157
|
+
created.disposeObservations();
|
|
158
|
+
throw error;
|
|
159
|
+
}
|
|
150
160
|
});
|
|
151
161
|
|
|
152
162
|
ChronicleMetrics.eventStoreRetrievals.add(1, {
|
|
@@ -156,12 +166,11 @@ export class ChronicleClient implements IChronicleClient {
|
|
|
156
166
|
span.setStatus({ code: SpanStatusCode.OK });
|
|
157
167
|
return store;
|
|
158
168
|
} catch (error) {
|
|
159
|
-
span
|
|
160
|
-
span.recordException(error as Error);
|
|
169
|
+
recordSafeException(span, error);
|
|
161
170
|
this._logger.error('Failed getting event store', {
|
|
162
171
|
eventStore: storeName.value,
|
|
163
172
|
namespace: namespaceName.value,
|
|
164
|
-
error
|
|
173
|
+
error
|
|
165
174
|
});
|
|
166
175
|
throw error;
|
|
167
176
|
} finally {
|
|
@@ -172,7 +181,7 @@ export class ChronicleClient implements IChronicleClient {
|
|
|
172
181
|
|
|
173
182
|
/** @inheritdoc */
|
|
174
183
|
async getEventStores(): Promise<EventStoreName[]> {
|
|
175
|
-
return
|
|
184
|
+
return observeOperation(WellKnownTelemetryNames.spans.getEventStores, async span => {
|
|
176
185
|
try {
|
|
177
186
|
const response = await this.withReconnect('get_event_stores', async () => {
|
|
178
187
|
await this.ensureConnected();
|
|
@@ -185,10 +194,9 @@ export class ChronicleClient implements IChronicleClient {
|
|
|
185
194
|
span.setStatus({ code: SpanStatusCode.OK });
|
|
186
195
|
return result;
|
|
187
196
|
} catch (error) {
|
|
188
|
-
span
|
|
189
|
-
span.recordException(error as Error);
|
|
197
|
+
recordSafeException(span, error);
|
|
190
198
|
this._logger.error('Failed retrieving event stores', {
|
|
191
|
-
error
|
|
199
|
+
error
|
|
192
200
|
});
|
|
193
201
|
throw error;
|
|
194
202
|
} finally {
|
|
@@ -210,7 +218,7 @@ export class ChronicleClient implements IChronicleClient {
|
|
|
210
218
|
if (this._lifecycle.isConnected) {
|
|
211
219
|
void this._lifecycle.disconnected(error => {
|
|
212
220
|
this._logger.error('Disconnected lifecycle callback failed during dispose', {
|
|
213
|
-
error
|
|
221
|
+
error
|
|
214
222
|
});
|
|
215
223
|
});
|
|
216
224
|
}
|
|
@@ -244,7 +252,7 @@ export class ChronicleClient implements IChronicleClient {
|
|
|
244
252
|
await this.startKernelKeepAlive();
|
|
245
253
|
await this._lifecycle.connected(error => {
|
|
246
254
|
this._logger.error('Connected lifecycle callback failed', {
|
|
247
|
-
error
|
|
255
|
+
error
|
|
248
256
|
});
|
|
249
257
|
});
|
|
250
258
|
return;
|
|
@@ -280,7 +288,7 @@ export class ChronicleClient implements IChronicleClient {
|
|
|
280
288
|
}
|
|
281
289
|
|
|
282
290
|
if (!this._connectOperation) {
|
|
283
|
-
this._connectOperation = this.connectWithRetry().finally(() => {
|
|
291
|
+
this._connectOperation = runInBackgroundContext(() => this.connectWithRetry()).finally(() => {
|
|
284
292
|
this._connectOperation = undefined;
|
|
285
293
|
});
|
|
286
294
|
}
|
|
@@ -292,16 +300,16 @@ export class ChronicleClient implements IChronicleClient {
|
|
|
292
300
|
if (this._connectionFailure) throw this._connectionFailure;
|
|
293
301
|
|
|
294
302
|
if (!this._reconnectOperation) {
|
|
295
|
-
this._reconnectOperation = (async () => {
|
|
303
|
+
this._reconnectOperation = runInBackgroundContext(async () => {
|
|
296
304
|
this._logger.warn('Reconnecting to Chronicle kernel', {
|
|
297
305
|
reason,
|
|
298
|
-
error
|
|
306
|
+
error
|
|
299
307
|
});
|
|
300
308
|
|
|
301
309
|
if (this._lifecycle.isConnected) {
|
|
302
310
|
await this._lifecycle.disconnected(disconnectError => {
|
|
303
311
|
this._logger.error('Disconnected lifecycle callback failed', {
|
|
304
|
-
error:
|
|
312
|
+
error: disconnectError
|
|
305
313
|
});
|
|
306
314
|
});
|
|
307
315
|
}
|
|
@@ -317,7 +325,7 @@ export class ChronicleClient implements IChronicleClient {
|
|
|
317
325
|
await this.startKernelKeepAlive();
|
|
318
326
|
await this._lifecycle.connected(connectedError => {
|
|
319
327
|
this._logger.error('Connected lifecycle callback failed after reconnect', {
|
|
320
|
-
error:
|
|
328
|
+
error: connectedError
|
|
321
329
|
});
|
|
322
330
|
});
|
|
323
331
|
return;
|
|
@@ -331,7 +339,7 @@ export class ChronicleClient implements IChronicleClient {
|
|
|
331
339
|
await this.backOff(attempt, 'Reconnect attempt failed, retrying', reconnectError);
|
|
332
340
|
}
|
|
333
341
|
}
|
|
334
|
-
})
|
|
342
|
+
}).finally(() => {
|
|
335
343
|
this._reconnectOperation = undefined;
|
|
336
344
|
});
|
|
337
345
|
}
|
|
@@ -351,7 +359,7 @@ export class ChronicleClient implements IChronicleClient {
|
|
|
351
359
|
this._logger.warn(message, {
|
|
352
360
|
attempt,
|
|
353
361
|
delayMs,
|
|
354
|
-
error
|
|
362
|
+
error
|
|
355
363
|
});
|
|
356
364
|
|
|
357
365
|
await new Promise(resolve => setTimeout(resolve, delayMs));
|
|
@@ -437,9 +445,9 @@ export class ChronicleClient implements IChronicleClient {
|
|
|
437
445
|
}
|
|
438
446
|
|
|
439
447
|
private startConnectionWatchdog(): void {
|
|
440
|
-
this._watchdogHandle = setInterval(() => {
|
|
448
|
+
this._watchdogHandle = runInBackgroundContext(() => setInterval(() => {
|
|
441
449
|
void this.runHealthCheck().catch(error => this.backgroundConnectionFailed('watchdog-health-check', error));
|
|
442
|
-
}, ChronicleClient._healthCheckIntervalMs);
|
|
450
|
+
}, ChronicleClient._healthCheckIntervalMs));
|
|
443
451
|
|
|
444
452
|
this._watchdogHandle.unref?.();
|
|
445
453
|
}
|
|
@@ -477,7 +485,7 @@ export class ChronicleClient implements IChronicleClient {
|
|
|
477
485
|
}
|
|
478
486
|
|
|
479
487
|
void this.reconnect(reason, error).catch(failure => this.backgroundConnectionFailed(reason, failure));
|
|
480
|
-
});
|
|
488
|
+
}, {}, this.options.logger);
|
|
481
489
|
|
|
482
490
|
await keepAlive.start(
|
|
483
491
|
{
|
|
@@ -511,7 +519,7 @@ export class ChronicleClient implements IChronicleClient {
|
|
|
511
519
|
this.failConnection(error instanceof Error ? error : new Error(String(error)));
|
|
512
520
|
this._logger.error('Background connection recovery failed; create a new client after correcting the server', {
|
|
513
521
|
reason,
|
|
514
|
-
error
|
|
522
|
+
error
|
|
515
523
|
});
|
|
516
524
|
}
|
|
517
525
|
|
package/ChronicleOptions.ts
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
// Copyright (c) Cratis. All rights reserved.
|
|
2
2
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
3
3
|
|
|
4
|
+
import { types } from 'node:util';
|
|
4
5
|
import { DefaultClientArtifactsProvider, IClientArtifactsProvider } from './artifacts/index.js';
|
|
5
6
|
import { ChronicleConnectionString } from './connection/index.js';
|
|
6
7
|
import { WellKnownSinks } from './sinks/index.js';
|
|
7
8
|
import type { ReactorResultHandler } from './reactors/ReactorResultHandler.js';
|
|
8
9
|
import type { ClientArtifactsActivator } from './artifacts/ClientArtifactsActivator.js';
|
|
9
10
|
import type { ReadModelNamingPolicy } from './readModels/ReadModelNamingPolicy.js';
|
|
11
|
+
import type { ChronicleTelemetryOptions } from './telemetry/ChronicleTelemetryOptions.js';
|
|
12
|
+
import type { IChronicleLogger } from './logging/IChronicleLogger.js';
|
|
10
13
|
|
|
11
14
|
type ChronicleOptionsConstructorParams = {
|
|
15
|
+
telemetry?: ChronicleTelemetryOptions;
|
|
16
|
+
logger?: IChronicleLogger;
|
|
12
17
|
connectionString: ChronicleConnectionString;
|
|
13
18
|
programIdentifier?: string;
|
|
14
19
|
softwareVersion?: string;
|
|
@@ -22,6 +27,8 @@ type ChronicleOptionsConstructorParams = {
|
|
|
22
27
|
};
|
|
23
28
|
|
|
24
29
|
type ChronicleOptionsFactoryParams = {
|
|
30
|
+
telemetry?: ChronicleTelemetryOptions;
|
|
31
|
+
logger?: IChronicleLogger;
|
|
25
32
|
clientArtifactsProvider?: IClientArtifactsProvider;
|
|
26
33
|
discoveryPatterns?: string[];
|
|
27
34
|
defaultSinkTypeId?: string;
|
|
@@ -34,6 +41,12 @@ type ChronicleOptionsFactoryParams = {
|
|
|
34
41
|
* Represents configuration options for the Chronicle client.
|
|
35
42
|
*/
|
|
36
43
|
export class ChronicleOptions {
|
|
44
|
+
/** Per-client telemetry privacy settings. Event source identifiers are omitted by default. */
|
|
45
|
+
readonly telemetry?: ChronicleTelemetryOptions;
|
|
46
|
+
|
|
47
|
+
/** Application diagnostic sink. Absent uses the OpenTelemetry diag compatibility adapter. */
|
|
48
|
+
readonly logger?: IChronicleLogger;
|
|
49
|
+
|
|
37
50
|
/**
|
|
38
51
|
* The connection string used to connect to the Chronicle Kernel.
|
|
39
52
|
*/
|
|
@@ -101,6 +114,17 @@ export class ChronicleOptions {
|
|
|
101
114
|
this.reactorResultHandler = options.reactorResultHandler;
|
|
102
115
|
this.artifactActivator = options.artifactActivator;
|
|
103
116
|
this.readModelNamingPolicy = options.readModelNamingPolicy;
|
|
117
|
+
const policy = options.telemetry?.eventSourceId;
|
|
118
|
+
if (policy !== undefined) {
|
|
119
|
+
if (policy?.mode !== 'raw' && policy?.mode !== 'hmac') {
|
|
120
|
+
throw new TypeError('telemetry.eventSourceId.mode must be raw or hmac.');
|
|
121
|
+
}
|
|
122
|
+
if (policy.mode === 'hmac' && (!types.isUint8Array(policy.key) || policy.key.byteLength === 0)) {
|
|
123
|
+
throw new TypeError('telemetry.eventSourceId.key must be a non-empty Uint8Array for hmac mode.');
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
this.telemetry = options.telemetry;
|
|
127
|
+
this.logger = options.logger;
|
|
104
128
|
}
|
|
105
129
|
|
|
106
130
|
private static defaultDiscoveryPatterns(): string[] {
|
|
@@ -144,7 +168,9 @@ export class ChronicleOptions {
|
|
|
144
168
|
defaultSinkTypeId: options?.defaultSinkTypeId,
|
|
145
169
|
reactorResultHandler: options?.reactorResultHandler,
|
|
146
170
|
artifactActivator: options?.artifactActivator,
|
|
147
|
-
readModelNamingPolicy: options?.readModelNamingPolicy
|
|
171
|
+
readModelNamingPolicy: options?.readModelNamingPolicy,
|
|
172
|
+
telemetry: options?.telemetry,
|
|
173
|
+
logger: options?.logger
|
|
148
174
|
});
|
|
149
175
|
}
|
|
150
176
|
|
package/EventStore.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
// Copyright (c) Cratis. All rights reserved.
|
|
2
2
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { createLogger } from './logging/createLogger.js';
|
|
5
|
+
import type { ChronicleTelemetryOptions } from './telemetry/ChronicleTelemetryOptions.js';
|
|
6
|
+
import { setTelemetryAttribute, recordSafeException } from './telemetry/spanAttributes.js';
|
|
7
|
+
import { WellKnownTelemetryNames } from './WellKnownTelemetryNames.js';
|
|
5
8
|
import { SpanStatusCode } from '@opentelemetry/api';
|
|
6
9
|
import { ChronicleConnection } from './connection/index.js';
|
|
7
10
|
import { ConnectionLifecycle } from './connection/ConnectionLifecycle.js';
|
|
@@ -21,6 +24,8 @@ import { IConstraints } from './events/constraints/IConstraints.js';
|
|
|
21
24
|
import { Projections } from './projections/Projections.js';
|
|
22
25
|
import { IProjections } from './projections/IProjections.js';
|
|
23
26
|
import { Reactors } from './reactors/Reactors.js';
|
|
27
|
+
import { getReactorEventTypes } from './reactors/ReactorDispatcher.js';
|
|
28
|
+
import { getEventHandlers } from './observation/getEventHandlers.js';
|
|
24
29
|
import type { ReactorResultHandler } from './reactors/ReactorResultHandler.js';
|
|
25
30
|
import type { ClientArtifactsActivator } from './artifacts/ClientArtifactsActivator.js';
|
|
26
31
|
import type { ReadModelNamingPolicy } from './readModels/ReadModelNamingPolicy.js';
|
|
@@ -31,7 +36,7 @@ import { IReadModels } from './readModels/IReadModels.js';
|
|
|
31
36
|
import { ReadModels } from './readModels/ReadModels.js';
|
|
32
37
|
import { EventSeeding } from './seeding/EventSeeding.js';
|
|
33
38
|
import { IEventSeeding } from './seeding/IEventSeeding.js';
|
|
34
|
-
import {
|
|
39
|
+
import { observeOperation } from './telemetry/observeOperation.js';
|
|
35
40
|
import { DefaultClientArtifactsProvider } from './artifacts/DefaultClientArtifactsProvider.js';
|
|
36
41
|
import type { IClientArtifactsProvider } from './artifacts/IClientArtifactsProvider.js';
|
|
37
42
|
import { validateArtifactSchemas } from './artifacts/validateArtifactSchemas.js';
|
|
@@ -59,9 +64,7 @@ import { Observers } from './observation/Observers.js';
|
|
|
59
64
|
* via gRPC using the provided {@link ChronicleConnection}.
|
|
60
65
|
*/
|
|
61
66
|
export class EventStore implements IEventStore {
|
|
62
|
-
private readonly _logger
|
|
63
|
-
namespace: '@cratis/chronicle/EventStore'
|
|
64
|
-
});
|
|
67
|
+
private readonly _logger: ReturnType<typeof createLogger>;
|
|
65
68
|
|
|
66
69
|
readonly eventLog: IEventLog;
|
|
67
70
|
readonly eventTypes: IEventTypes;
|
|
@@ -93,15 +96,17 @@ export class EventStore implements IEventStore {
|
|
|
93
96
|
private readonly _artifacts: IClientArtifactsProvider = DefaultClientArtifactsProvider.default,
|
|
94
97
|
reactorResultHandler?: ReactorResultHandler,
|
|
95
98
|
artifactActivator?: ClientArtifactsActivator,
|
|
96
|
-
readModelNamingPolicy?: ReadModelNamingPolicy
|
|
99
|
+
readModelNamingPolicy?: ReadModelNamingPolicy,
|
|
100
|
+
private readonly _telemetry?: ChronicleTelemetryOptions
|
|
97
101
|
) {
|
|
102
|
+
this._logger = createLogger('@cratis/chronicle/EventStore', _connection.logger);
|
|
98
103
|
this.unitOfWorkManager = new UnitOfWorkManager(this);
|
|
99
104
|
|
|
100
105
|
const artifacts = this._artifacts;
|
|
101
106
|
this._constraints = new Constraints(name.value, _connection, artifacts);
|
|
102
107
|
this.constraints = this._constraints;
|
|
103
108
|
const resolveConstraintMessage = this._constraints.resolveMessageFor.bind(this._constraints);
|
|
104
|
-
this.eventLog = new EventLog(name.value, namespace.value, _connection, this.unitOfWorkManager, resolveConstraintMessage);
|
|
109
|
+
this.eventLog = new EventLog(name.value, namespace.value, _connection, this.unitOfWorkManager, resolveConstraintMessage, _telemetry);
|
|
105
110
|
this._sequences.set(EventSequenceId.eventLog.value, this.eventLog);
|
|
106
111
|
|
|
107
112
|
this.eventTypes = new EventTypes(name.value, _connection, artifacts);
|
|
@@ -142,6 +147,12 @@ export class EventStore implements IEventStore {
|
|
|
142
147
|
]);
|
|
143
148
|
|
|
144
149
|
validateArtifactSchemas(this._artifacts);
|
|
150
|
+
for (const type of this._artifacts.reactors) {
|
|
151
|
+
getReactorEventTypes(type, this._artifacts.eventTypes);
|
|
152
|
+
}
|
|
153
|
+
for (const type of this._artifacts.reducers) {
|
|
154
|
+
getEventHandlers(type, this._artifacts.eventTypes);
|
|
155
|
+
}
|
|
145
156
|
|
|
146
157
|
this._logger.debug('Registering discovered artifacts', {
|
|
147
158
|
eventStore: this.name.value,
|
|
@@ -180,7 +191,7 @@ export class EventStore implements IEventStore {
|
|
|
180
191
|
|
|
181
192
|
const sequence = new EventSequence(
|
|
182
193
|
id, this.name.value, this.namespace.value, this._connection, this.unitOfWorkManager,
|
|
183
|
-
this._constraints.resolveMessageFor.bind(this._constraints)
|
|
194
|
+
this._constraints.resolveMessageFor.bind(this._constraints), this._telemetry
|
|
184
195
|
);
|
|
185
196
|
this._sequences.set(id.value, sequence);
|
|
186
197
|
return sequence;
|
|
@@ -188,16 +199,15 @@ export class EventStore implements IEventStore {
|
|
|
188
199
|
|
|
189
200
|
/** @inheritdoc */
|
|
190
201
|
async getNamespaces(): Promise<EventStoreNamespaceName[]> {
|
|
191
|
-
return
|
|
192
|
-
span
|
|
202
|
+
return observeOperation(WellKnownTelemetryNames.spans.getNamespaces, async span => {
|
|
203
|
+
setTelemetryAttribute(span, 'eventStore', this.name.value);
|
|
193
204
|
try {
|
|
194
205
|
const response = await this._connection.namespaces.allNamespaces({ EventStore: this.name.value });
|
|
195
206
|
const result = ensureQuerySuccess('get namespaces', response).map(namespace => new EventStoreNamespaceName(namespace.Name));
|
|
196
207
|
span.setStatus({ code: SpanStatusCode.OK });
|
|
197
208
|
return result;
|
|
198
209
|
} catch (error) {
|
|
199
|
-
span
|
|
200
|
-
span.recordException(error as Error);
|
|
210
|
+
recordSafeException(span, error);
|
|
201
211
|
throw error;
|
|
202
212
|
} finally {
|
|
203
213
|
span.end();
|
package/Metrics.ts
CHANGED
|
@@ -1,109 +1,83 @@
|
|
|
1
1
|
// Copyright (c) Cratis. All rights reserved.
|
|
2
2
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
3
3
|
|
|
4
|
-
import { metrics } from '@opentelemetry/api';
|
|
4
|
+
import { metrics, type Attributes, type Counter, type Histogram } from '@opentelemetry/api';
|
|
5
|
+
import { clientVersion } from './connection/clientVersion.js';
|
|
6
|
+
import { WellKnownTelemetryNames as names } from './WellKnownTelemetryNames.js';
|
|
5
7
|
|
|
6
|
-
/**
|
|
7
|
-
|
|
8
|
-
* This matches {@link ChronicleInstrumentationName} from Tracing so that all Chronicle
|
|
9
|
-
* telemetry is grouped under a single instrumentation scope in your observability backend.
|
|
10
|
-
*/
|
|
11
|
-
export const ChronicleMeterName = '@cratis/chronicle';
|
|
8
|
+
/** The versioned instrumentation scope shared by Chronicle client traces and metrics. */
|
|
9
|
+
export const ChronicleMeterName = names.scope;
|
|
12
10
|
|
|
13
|
-
/**
|
|
14
|
-
|
|
15
|
-
*
|
|
16
|
-
* If your application has configured an OpenTelemetry SDK (e.g. via {@link https://www.npmjs.com/package/@opentelemetry/sdk-node}),
|
|
17
|
-
* Chronicle metrics will automatically flow through it.
|
|
18
|
-
* If no SDK is configured, the no-op meter is used and no overhead is incurred.
|
|
19
|
-
*/
|
|
20
|
-
export const ChronicleMeter = metrics.getMeter(ChronicleMeterName);
|
|
11
|
+
/** The Chronicle meter. Applications own SDK configuration and export. */
|
|
12
|
+
export const ChronicleMeter = metrics.getMeter(ChronicleMeterName, clientVersion);
|
|
21
13
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
* Counts the number of individual events appended to an event sequence.
|
|
29
|
-
*
|
|
30
|
-
* Attributes: `chronicle.event_store`, `chronicle.namespace`,
|
|
31
|
-
* `chronicle.event_sequence_id`, `chronicle.event_type_id`
|
|
32
|
-
*/
|
|
33
|
-
eventsAppended: ChronicleMeter.createCounter('chronicle.events.appended', {
|
|
34
|
-
description: 'Number of individual events appended to an event sequence.',
|
|
35
|
-
unit: '{event}'
|
|
36
|
-
}),
|
|
14
|
+
// Resolve instruments at recording time: the OTel metrics API does not proxy a meter
|
|
15
|
+
// acquired before the application installs its provider. SDKs cache these instruments.
|
|
16
|
+
function counter(name: string, description: string, unit: string): Counter {
|
|
17
|
+
return { add: (value, attributes, context) => metrics.getMeter(ChronicleMeterName, clientVersion)
|
|
18
|
+
.createCounter(name, { description, unit }).add(value, attributes, context) };
|
|
19
|
+
}
|
|
37
20
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
unit: '{operation}'
|
|
48
|
-
}),
|
|
21
|
+
function duration(name: string, unit: 's' | 'ms'): Histogram {
|
|
22
|
+
const scale = unit === 's' ? 0.001 : 1;
|
|
23
|
+
return { record: (value, attributes, context) => metrics.getMeter(ChronicleMeterName, clientVersion)
|
|
24
|
+
.createHistogram(name, {
|
|
25
|
+
description: 'Duration of completed event append RPCs, including returned rejections.',
|
|
26
|
+
unit,
|
|
27
|
+
advice: { explicitBucketBoundaries: [1, 5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000].map(value => value * scale) }
|
|
28
|
+
}).record(value, attributes, context) };
|
|
29
|
+
}
|
|
49
30
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
})
|
|
31
|
+
/** Shared-convention instruments. Durations are seconds; batch size is not a dimension. */
|
|
32
|
+
export const ChronicleConventionMetrics = {
|
|
33
|
+
eventsAppended: counter(names.metrics.eventsAppended, 'Number of individual events appended to an event sequence.', '{event}'),
|
|
34
|
+
batchAppendsPerformed: counter(names.metrics.batchAppendsPerformed, 'Number of batch-append operations.', '{operation}'),
|
|
35
|
+
eventStoreRetrievals: counter(names.metrics.eventStoreRetrievals, 'Number of event store retrieval operations.', '{operation}'),
|
|
36
|
+
appendDuration: duration(names.metrics.appendDuration, 's'),
|
|
37
|
+
appendManyDuration: duration(names.metrics.appendManyDuration, 's'),
|
|
38
|
+
constraintViolations: counter(names.metrics.constraintViolations, 'Number of constraint violations encountered during event appends.', '{violation}'),
|
|
39
|
+
appendErrors: counter(names.metrics.appendErrors, 'Number of errors encountered during event appends.', '{error}')
|
|
40
|
+
};
|
|
59
41
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
advice: {
|
|
70
|
-
explicitBucketBoundaries: [1, 5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000]
|
|
71
|
-
}
|
|
72
|
-
}),
|
|
42
|
+
/** Only the existing bounded-by-configuration dimensions belong on the new instruments. */
|
|
43
|
+
function sharedAttributes(attributes: Attributes = {}): Attributes {
|
|
44
|
+
const result: Attributes = {};
|
|
45
|
+
for (const name of ['eventStore', 'namespace', 'eventSequenceId', 'eventTypeId'] as const) {
|
|
46
|
+
const value = attributes[names.attributes[name]] ?? attributes[names.legacyAttributes[name]];
|
|
47
|
+
if (value !== undefined) result[names.attributes[name]] = value;
|
|
48
|
+
}
|
|
49
|
+
return result;
|
|
50
|
+
}
|
|
73
51
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
appendManyDuration: ChronicleMeter.createHistogram('chronicle.events.append_many_duration', {
|
|
81
|
-
description: 'Duration of batch event append operations.',
|
|
82
|
-
unit: 'ms',
|
|
83
|
-
advice: {
|
|
84
|
-
explicitBucketBoundaries: [1, 5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000]
|
|
85
|
-
}
|
|
86
|
-
}),
|
|
52
|
+
function bridgeCounter(legacy: Counter, shared: Counter): Counter {
|
|
53
|
+
return { add: (value, attributes, context) => {
|
|
54
|
+
legacy.add(value, attributes, context);
|
|
55
|
+
shared.add(value, sharedAttributes(attributes), context);
|
|
56
|
+
} };
|
|
57
|
+
}
|
|
87
58
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
constraintViolations: ChronicleMeter.createCounter('chronicle.events.constraint_violations', {
|
|
95
|
-
description: 'Number of constraint violations encountered during event appends.',
|
|
96
|
-
unit: '{violation}'
|
|
97
|
-
}),
|
|
59
|
+
function bridgeDuration(legacy: Histogram, shared: Histogram): Histogram {
|
|
60
|
+
return { record: (milliseconds, attributes, context) => {
|
|
61
|
+
legacy.record(milliseconds, attributes, context);
|
|
62
|
+
shared.record(milliseconds / 1000, sharedAttributes(attributes), context);
|
|
63
|
+
} };
|
|
64
|
+
}
|
|
98
65
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
66
|
+
/**
|
|
67
|
+
* Compatibility instruments: existing callers still record milliseconds and legacy attributes.
|
|
68
|
+
* Each measurement also records its shared-convention equivalent, without adding sensitive dimensions.
|
|
69
|
+
*/
|
|
70
|
+
export const ChronicleMetrics = {
|
|
71
|
+
eventsAppended: bridgeCounter(counter(names.legacyMetrics.eventsAppended,
|
|
72
|
+
'Number of individual events appended to an event sequence.', '{event}'), ChronicleConventionMetrics.eventsAppended),
|
|
73
|
+
batchAppendsPerformed: bridgeCounter(counter(names.legacyMetrics.batchAppendsPerformed,
|
|
74
|
+
'Number of batch-append operations.', '{operation}'), ChronicleConventionMetrics.batchAppendsPerformed),
|
|
75
|
+
eventStoreRetrievals: bridgeCounter(counter(names.legacyMetrics.eventStoreRetrievals,
|
|
76
|
+
'Number of event store retrieval operations.', '{operation}'), ChronicleConventionMetrics.eventStoreRetrievals),
|
|
77
|
+
appendDuration: bridgeDuration(duration(names.legacyMetrics.appendDuration, 'ms'), ChronicleConventionMetrics.appendDuration),
|
|
78
|
+
appendManyDuration: bridgeDuration(duration(names.legacyMetrics.appendManyDuration, 'ms'), ChronicleConventionMetrics.appendManyDuration),
|
|
79
|
+
constraintViolations: bridgeCounter(counter(names.legacyMetrics.constraintViolations,
|
|
80
|
+
'Number of constraint violations encountered during event appends.', '{violation}'), ChronicleConventionMetrics.constraintViolations),
|
|
81
|
+
appendErrors: bridgeCounter(counter(names.legacyMetrics.appendErrors,
|
|
82
|
+
'Number of errors encountered during event appends.', '{error}'), ChronicleConventionMetrics.appendErrors)
|
|
109
83
|
};
|
package/Tracing.ts
CHANGED
|
@@ -2,12 +2,14 @@
|
|
|
2
2
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
3
3
|
|
|
4
4
|
import { trace } from '@opentelemetry/api';
|
|
5
|
+
import { clientVersion } from './connection/clientVersion.js';
|
|
6
|
+
import { WellKnownTelemetryNames } from './WellKnownTelemetryNames.js';
|
|
5
7
|
|
|
6
8
|
/**
|
|
7
9
|
* The name of the Chronicle instrumentation library.
|
|
8
10
|
* Use this name to filter or configure Chronicle client spans in your observability backend.
|
|
9
11
|
*/
|
|
10
|
-
export const ChronicleInstrumentationName =
|
|
12
|
+
export const ChronicleInstrumentationName = WellKnownTelemetryNames.scope;
|
|
11
13
|
|
|
12
14
|
/**
|
|
13
15
|
* The OpenTelemetry tracer used by the Chronicle client for all instrumentation.
|
|
@@ -18,4 +20,4 @@ export const ChronicleInstrumentationName = '@cratis/chronicle';
|
|
|
18
20
|
* Chronicle spans will automatically flow through it.
|
|
19
21
|
* If no SDK is configured, the no-op tracer is used and no overhead is incurred.
|
|
20
22
|
*/
|
|
21
|
-
export const ChronicleTracer = trace.getTracer(ChronicleInstrumentationName);
|
|
23
|
+
export const ChronicleTracer = trace.getTracer(ChronicleInstrumentationName, clientVersion);
|