@contractspec/lib.observability 3.7.6 → 3.7.10

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/dist/index.js CHANGED
@@ -148,241 +148,6 @@ class RootCauseAnalyzer {
148
148
  }
149
149
  }
150
150
 
151
- // src/tracing/core.ts
152
- import {
153
- SpanStatusCode,
154
- trace
155
- } from "@opentelemetry/api";
156
- var DEFAULT_TRACER_NAME = "@contractspec/lib.observability";
157
- function getTracer(name = DEFAULT_TRACER_NAME) {
158
- return trace.getTracer(name);
159
- }
160
- async function traceAsync(name, fn, tracerName) {
161
- const tracer = getTracer(tracerName);
162
- return tracer.startActiveSpan(name, async (span) => {
163
- try {
164
- const result = await fn(span);
165
- span.setStatus({ code: SpanStatusCode.OK });
166
- return result;
167
- } catch (error) {
168
- span.recordException(error);
169
- span.setStatus({
170
- code: SpanStatusCode.ERROR,
171
- message: error instanceof Error ? error.message : String(error)
172
- });
173
- throw error;
174
- } finally {
175
- span.end();
176
- }
177
- });
178
- }
179
- function traceSync(name, fn, tracerName) {
180
- const tracer = getTracer(tracerName);
181
- return tracer.startActiveSpan(name, (span) => {
182
- try {
183
- const result = fn(span);
184
- span.setStatus({ code: SpanStatusCode.OK });
185
- return result;
186
- } catch (error) {
187
- span.recordException(error);
188
- span.setStatus({
189
- code: SpanStatusCode.ERROR,
190
- message: error instanceof Error ? error.message : String(error)
191
- });
192
- throw error;
193
- } finally {
194
- span.end();
195
- }
196
- });
197
- }
198
-
199
- // src/tracing/model-selection.span.ts
200
- async function traceModelSelection(fn, input) {
201
- const startMs = performance.now();
202
- return traceAsync("model.selection", async (span) => {
203
- const result = await fn();
204
- const durationMs = performance.now() - startMs;
205
- span.setAttribute("model.selected", input.modelId);
206
- span.setAttribute("model.provider", input.providerKey);
207
- span.setAttribute("model.score", input.score);
208
- span.setAttribute("model.alternatives_count", input.alternativesCount);
209
- span.setAttribute("model.selection_duration_ms", durationMs);
210
- span.setAttribute("model.reason", input.reason);
211
- if (input.dimension) {
212
- span.setAttribute("model.dimension", input.dimension);
213
- }
214
- if (input.constraints) {
215
- span.setAttribute("model.constraints", JSON.stringify(input.constraints));
216
- }
217
- return result;
218
- });
219
- }
220
- // src/telemetry/model-selection-telemetry.ts
221
- class ModelSelectionTelemetry {
222
- provider;
223
- eventName;
224
- constructor(provider, options) {
225
- this.provider = provider;
226
- this.eventName = options?.eventName ?? "$model_selection";
227
- }
228
- async trackSelection(distinctId, properties) {
229
- await this.provider.capture({
230
- distinctId,
231
- event: this.eventName,
232
- timestamp: new Date,
233
- properties: {
234
- $model_id: properties.modelId,
235
- $model_provider: properties.providerKey,
236
- $model_score: properties.score,
237
- $model_dimension: properties.dimension ?? null,
238
- $model_reason: properties.reason,
239
- $model_alternatives_count: properties.alternativesCount,
240
- $model_cost_estimate_input: properties.costEstimateInput ?? null,
241
- $model_cost_estimate_output: properties.costEstimateOutput ?? null,
242
- $model_selection_duration_ms: properties.selectionDurationMs ?? null
243
- }
244
- });
245
- }
246
- }
247
-
248
- // src/metrics/index.ts
249
- import {
250
- metrics
251
- } from "@opentelemetry/api";
252
- var DEFAULT_METER_NAME = "@contractspec/lib.observability";
253
- function getMeter(name = DEFAULT_METER_NAME) {
254
- return metrics.getMeter(name);
255
- }
256
- function createCounter(name, description, meterName) {
257
- return getMeter(meterName).createCounter(name, { description });
258
- }
259
- function createUpDownCounter(name, description, meterName) {
260
- return getMeter(meterName).createUpDownCounter(name, { description });
261
- }
262
- function createHistogram(name, description, meterName) {
263
- return getMeter(meterName).createHistogram(name, { description });
264
- }
265
- var standardMetrics = {
266
- httpRequests: createCounter("http_requests_total", "Total HTTP requests"),
267
- httpDuration: createHistogram("http_request_duration_seconds", "HTTP request duration"),
268
- operationErrors: createCounter("operation_errors_total", "Total operation errors"),
269
- workflowDuration: createHistogram("workflow_duration_seconds", "Workflow execution duration")
270
- };
271
-
272
- // src/logging/index.ts
273
- import { trace as trace2, context } from "@opentelemetry/api";
274
-
275
- class Logger {
276
- serviceName;
277
- constructor(serviceName) {
278
- this.serviceName = serviceName;
279
- }
280
- log(level, message, meta = {}) {
281
- const span = trace2.getSpan(context.active());
282
- const traceId = span?.spanContext().traceId;
283
- const spanId = span?.spanContext().spanId;
284
- const entry = {
285
- timestamp: new Date().toISOString(),
286
- service: this.serviceName,
287
- level,
288
- message,
289
- traceId,
290
- spanId,
291
- ...meta
292
- };
293
- console.log(JSON.stringify(entry));
294
- }
295
- debug(message, meta) {
296
- this.log("debug", message, meta);
297
- }
298
- info(message, meta) {
299
- this.log("info", message, meta);
300
- }
301
- warn(message, meta) {
302
- this.log("warn", message, meta);
303
- }
304
- error(message, meta) {
305
- this.log("error", message, meta);
306
- }
307
- }
308
- var logger = new Logger(process.env.OTEL_SERVICE_NAME || "unknown-service");
309
-
310
- // src/tracing/middleware.ts
311
- function createTracingMiddleware(options = {}) {
312
- return async (req, next) => {
313
- const method = req.method;
314
- const url = new URL(req.url);
315
- const path = url.pathname;
316
- standardMetrics.httpRequests.add(1, { method, path });
317
- const startTime = performance.now();
318
- return traceAsync(`HTTP ${method} ${path}`, async (span) => {
319
- span.setAttribute("http.method", method);
320
- span.setAttribute("http.url", req.url);
321
- try {
322
- const response = await next();
323
- span.setAttribute("http.status_code", response.status);
324
- const duration = (performance.now() - startTime) / 1000;
325
- standardMetrics.httpDuration.record(duration, {
326
- method,
327
- path,
328
- status: response.status.toString()
329
- });
330
- emitTelemetrySample({
331
- req,
332
- res: response,
333
- span,
334
- success: true,
335
- durationMs: duration * 1000,
336
- options
337
- });
338
- return response;
339
- } catch (error) {
340
- standardMetrics.operationErrors.add(1, { method, path });
341
- emitTelemetrySample({
342
- req,
343
- span,
344
- success: false,
345
- durationMs: performance.now() - startTime,
346
- error,
347
- options
348
- });
349
- throw error;
350
- }
351
- });
352
- };
353
- }
354
- function emitTelemetrySample({
355
- req,
356
- res,
357
- span,
358
- success,
359
- durationMs,
360
- error,
361
- options
362
- }) {
363
- if (!options.onSample || !options.resolveOperation)
364
- return;
365
- const operation = options.resolveOperation({ req, res });
366
- if (!operation)
367
- return;
368
- const sample = {
369
- operation,
370
- durationMs,
371
- success,
372
- timestamp: new Date,
373
- errorCode: !success && error instanceof Error ? error.name : success ? undefined : "unknown",
374
- tenantId: options.tenantResolver?.(req),
375
- actorId: options.actorResolver?.(req),
376
- traceId: span.spanContext().traceId,
377
- metadata: {
378
- method: req.method,
379
- path: new URL(req.url).pathname,
380
- status: res?.status
381
- }
382
- };
383
- options.onSample(sample);
384
- }
385
-
386
151
  // src/intent/aggregator.ts
387
152
  var DEFAULT_WINDOW_MS = 15 * 60 * 1000;
388
153
 
@@ -401,11 +166,11 @@ class IntentAggregator {
401
166
  const minTimestamp = now.getTime() - this.windowMs;
402
167
  const windowSamples = this.samples.filter((sample) => sample.timestamp.getTime() >= minTimestamp);
403
168
  this.samples.length = 0;
404
- const metrics2 = this.aggregateMetrics(windowSamples);
169
+ const metrics = this.aggregateMetrics(windowSamples);
405
170
  const sequences = this.buildSequences(windowSamples);
406
171
  const timestamps = windowSamples.map((sample) => sample.timestamp.getTime());
407
172
  return {
408
- metrics: metrics2,
173
+ metrics,
409
174
  sequences,
410
175
  sampleCount: windowSamples.length,
411
176
  windowStart: timestamps.length ? new Date(Math.min(...timestamps)) : undefined,
@@ -620,6 +385,68 @@ class IntentDetector {
620
385
  }
621
386
  }
622
387
 
388
+ // src/logging/index.ts
389
+ import { context, trace } from "@opentelemetry/api";
390
+
391
+ class Logger {
392
+ serviceName;
393
+ constructor(serviceName) {
394
+ this.serviceName = serviceName;
395
+ }
396
+ log(level, message, meta = {}) {
397
+ const span = trace.getSpan(context.active());
398
+ const traceId = span?.spanContext().traceId;
399
+ const spanId = span?.spanContext().spanId;
400
+ const entry = {
401
+ timestamp: new Date().toISOString(),
402
+ service: this.serviceName,
403
+ level,
404
+ message,
405
+ traceId,
406
+ spanId,
407
+ ...meta
408
+ };
409
+ console.log(JSON.stringify(entry));
410
+ }
411
+ debug(message, meta) {
412
+ this.log("debug", message, meta);
413
+ }
414
+ info(message, meta) {
415
+ this.log("info", message, meta);
416
+ }
417
+ warn(message, meta) {
418
+ this.log("warn", message, meta);
419
+ }
420
+ error(message, meta) {
421
+ this.log("error", message, meta);
422
+ }
423
+ }
424
+ var logger = new Logger(process.env.OTEL_SERVICE_NAME || "unknown-service");
425
+
426
+ // src/metrics/index.ts
427
+ import {
428
+ metrics
429
+ } from "@opentelemetry/api";
430
+ var DEFAULT_METER_NAME = "@contractspec/lib.observability";
431
+ function getMeter(name = DEFAULT_METER_NAME) {
432
+ return metrics.getMeter(name);
433
+ }
434
+ function createCounter(name, description, meterName) {
435
+ return getMeter(meterName).createCounter(name, { description });
436
+ }
437
+ function createUpDownCounter(name, description, meterName) {
438
+ return getMeter(meterName).createUpDownCounter(name, { description });
439
+ }
440
+ function createHistogram(name, description, meterName) {
441
+ return getMeter(meterName).createHistogram(name, { description });
442
+ }
443
+ var standardMetrics = {
444
+ httpRequests: createCounter("http_requests_total", "Total HTTP requests"),
445
+ httpDuration: createHistogram("http_request_duration_seconds", "HTTP request duration"),
446
+ operationErrors: createCounter("operation_errors_total", "Total operation errors"),
447
+ workflowDuration: createHistogram("workflow_duration_seconds", "Workflow execution duration")
448
+ };
449
+
623
450
  // src/pipeline/evolution-pipeline.ts
624
451
  import { EventEmitter } from "events";
625
452
  class EvolutionPipeline {
@@ -727,71 +554,41 @@ class LifecycleKpiPipeline {
727
554
  if (previous !== undefined) {
728
555
  this.stageUpDownCounter.add(-1, {
729
556
  stage: getStageLabel(previous),
730
- tenantId
731
- });
732
- }
733
- this.stageUpDownCounter.add(1, { stage: getStageLabel(stage), tenantId });
734
- this.currentStageByTenant.set(tenantId, stage);
735
- this.emitter.emit("event", {
736
- type: "stage.changed",
737
- payload: { tenantId, previousStage: previous, nextStage: stage }
738
- });
739
- }
740
- }
741
-
742
- // src/telemetry/posthog-telemetry.ts
743
- class PosthogTelemetryProvider {
744
- provider;
745
- eventPrefix;
746
- includeMetadata;
747
- constructor(provider, options = {}) {
748
- this.provider = provider;
749
- this.eventPrefix = options.eventPrefix ?? "observability";
750
- this.includeMetadata = options.includeMetadata ?? false;
751
- }
752
- async captureSample(sample) {
753
- await this.provider.capture({
754
- distinctId: sample.actorId ?? sample.tenantId ?? "unknown",
755
- event: `${this.eventPrefix}.operation`,
756
- timestamp: sample.timestamp,
757
- properties: {
758
- operation: sample.operation.name,
759
- version: sample.operation.version,
760
- durationMs: sample.durationMs,
761
- success: sample.success,
762
- errorCode: sample.errorCode ?? null,
763
- tenantId: sample.tenantId ?? null,
764
- traceId: sample.traceId ?? null,
765
- ...this.includeMetadata && sample.metadata ? { metadata: sample.metadata } : {}
766
- }
557
+ tenantId
558
+ });
559
+ }
560
+ this.stageUpDownCounter.add(1, { stage: getStageLabel(stage), tenantId });
561
+ this.currentStageByTenant.set(tenantId, stage);
562
+ this.emitter.emit("event", {
563
+ type: "stage.changed",
564
+ payload: { tenantId, previousStage: previous, nextStage: stage }
767
565
  });
768
566
  }
769
- async captureSnapshot(snapshot) {
567
+ }
568
+
569
+ // src/telemetry/model-selection-telemetry.ts
570
+ class ModelSelectionTelemetry {
571
+ provider;
572
+ eventName;
573
+ constructor(provider, options) {
574
+ this.provider = provider;
575
+ this.eventName = options?.eventName ?? "$model_selection";
576
+ }
577
+ async trackSelection(distinctId, properties) {
770
578
  await this.provider.capture({
771
- distinctId: "system",
772
- event: `${this.eventPrefix}.window`,
773
- timestamp: snapshot.windowEnd ?? new Date,
579
+ distinctId,
580
+ event: this.eventName,
581
+ timestamp: new Date,
774
582
  properties: {
775
- sampleCount: snapshot.sampleCount,
776
- metricsCount: snapshot.metrics.length,
777
- sequencesCount: snapshot.sequences.length,
778
- windowStart: snapshot.windowStart?.toISOString() ?? null,
779
- windowEnd: snapshot.windowEnd?.toISOString() ?? null,
780
- ...this.includeMetadata ? {
781
- metrics: snapshot.metrics.map((metric) => ({
782
- operation: metric.operation.name,
783
- version: metric.operation.version,
784
- totalCalls: metric.totalCalls,
785
- successRate: metric.successRate,
786
- errorRate: metric.errorRate,
787
- averageLatencyMs: metric.averageLatencyMs,
788
- p95LatencyMs: metric.p95LatencyMs,
789
- p99LatencyMs: metric.p99LatencyMs,
790
- maxLatencyMs: metric.maxLatencyMs,
791
- topErrors: metric.topErrors
792
- })),
793
- sequences: snapshot.sequences
794
- } : {}
583
+ $model_id: properties.modelId,
584
+ $model_provider: properties.providerKey,
585
+ $model_score: properties.score,
586
+ $model_dimension: properties.dimension ?? null,
587
+ $model_reason: properties.reason,
588
+ $model_alternatives_count: properties.alternativesCount,
589
+ $model_cost_estimate_input: properties.costEstimateInput ?? null,
590
+ $model_cost_estimate_output: properties.costEstimateOutput ?? null,
591
+ $model_selection_duration_ms: properties.selectionDurationMs ?? null
795
592
  }
796
593
  });
797
594
  }
@@ -1102,6 +899,209 @@ function toDate(value) {
1102
899
  function isRecord(value) {
1103
900
  return typeof value === "object" && value !== null;
1104
901
  }
902
+
903
+ // src/telemetry/posthog-telemetry.ts
904
+ class PosthogTelemetryProvider {
905
+ provider;
906
+ eventPrefix;
907
+ includeMetadata;
908
+ constructor(provider, options = {}) {
909
+ this.provider = provider;
910
+ this.eventPrefix = options.eventPrefix ?? "observability";
911
+ this.includeMetadata = options.includeMetadata ?? false;
912
+ }
913
+ async captureSample(sample) {
914
+ await this.provider.capture({
915
+ distinctId: sample.actorId ?? sample.tenantId ?? "unknown",
916
+ event: `${this.eventPrefix}.operation`,
917
+ timestamp: sample.timestamp,
918
+ properties: {
919
+ operation: sample.operation.name,
920
+ version: sample.operation.version,
921
+ durationMs: sample.durationMs,
922
+ success: sample.success,
923
+ errorCode: sample.errorCode ?? null,
924
+ tenantId: sample.tenantId ?? null,
925
+ traceId: sample.traceId ?? null,
926
+ ...this.includeMetadata && sample.metadata ? { metadata: sample.metadata } : {}
927
+ }
928
+ });
929
+ }
930
+ async captureSnapshot(snapshot) {
931
+ await this.provider.capture({
932
+ distinctId: "system",
933
+ event: `${this.eventPrefix}.window`,
934
+ timestamp: snapshot.windowEnd ?? new Date,
935
+ properties: {
936
+ sampleCount: snapshot.sampleCount,
937
+ metricsCount: snapshot.metrics.length,
938
+ sequencesCount: snapshot.sequences.length,
939
+ windowStart: snapshot.windowStart?.toISOString() ?? null,
940
+ windowEnd: snapshot.windowEnd?.toISOString() ?? null,
941
+ ...this.includeMetadata ? {
942
+ metrics: snapshot.metrics.map((metric) => ({
943
+ operation: metric.operation.name,
944
+ version: metric.operation.version,
945
+ totalCalls: metric.totalCalls,
946
+ successRate: metric.successRate,
947
+ errorRate: metric.errorRate,
948
+ averageLatencyMs: metric.averageLatencyMs,
949
+ p95LatencyMs: metric.p95LatencyMs,
950
+ p99LatencyMs: metric.p99LatencyMs,
951
+ maxLatencyMs: metric.maxLatencyMs,
952
+ topErrors: metric.topErrors
953
+ })),
954
+ sequences: snapshot.sequences
955
+ } : {}
956
+ }
957
+ });
958
+ }
959
+ }
960
+
961
+ // src/tracing/core.ts
962
+ import {
963
+ SpanStatusCode,
964
+ trace as trace2
965
+ } from "@opentelemetry/api";
966
+ var DEFAULT_TRACER_NAME = "@contractspec/lib.observability";
967
+ function getTracer(name = DEFAULT_TRACER_NAME) {
968
+ return trace2.getTracer(name);
969
+ }
970
+ async function traceAsync(name, fn, tracerName) {
971
+ const tracer = getTracer(tracerName);
972
+ return tracer.startActiveSpan(name, async (span) => {
973
+ try {
974
+ const result = await fn(span);
975
+ span.setStatus({ code: SpanStatusCode.OK });
976
+ return result;
977
+ } catch (error) {
978
+ span.recordException(error);
979
+ span.setStatus({
980
+ code: SpanStatusCode.ERROR,
981
+ message: error instanceof Error ? error.message : String(error)
982
+ });
983
+ throw error;
984
+ } finally {
985
+ span.end();
986
+ }
987
+ });
988
+ }
989
+ function traceSync(name, fn, tracerName) {
990
+ const tracer = getTracer(tracerName);
991
+ return tracer.startActiveSpan(name, (span) => {
992
+ try {
993
+ const result = fn(span);
994
+ span.setStatus({ code: SpanStatusCode.OK });
995
+ return result;
996
+ } catch (error) {
997
+ span.recordException(error);
998
+ span.setStatus({
999
+ code: SpanStatusCode.ERROR,
1000
+ message: error instanceof Error ? error.message : String(error)
1001
+ });
1002
+ throw error;
1003
+ } finally {
1004
+ span.end();
1005
+ }
1006
+ });
1007
+ }
1008
+
1009
+ // src/tracing/model-selection.span.ts
1010
+ async function traceModelSelection(fn, input) {
1011
+ const startMs = performance.now();
1012
+ return traceAsync("model.selection", async (span) => {
1013
+ const result = await fn();
1014
+ const durationMs = performance.now() - startMs;
1015
+ span.setAttribute("model.selected", input.modelId);
1016
+ span.setAttribute("model.provider", input.providerKey);
1017
+ span.setAttribute("model.score", input.score);
1018
+ span.setAttribute("model.alternatives_count", input.alternativesCount);
1019
+ span.setAttribute("model.selection_duration_ms", durationMs);
1020
+ span.setAttribute("model.reason", input.reason);
1021
+ if (input.dimension) {
1022
+ span.setAttribute("model.dimension", input.dimension);
1023
+ }
1024
+ if (input.constraints) {
1025
+ span.setAttribute("model.constraints", JSON.stringify(input.constraints));
1026
+ }
1027
+ return result;
1028
+ });
1029
+ }
1030
+ // src/tracing/middleware.ts
1031
+ function createTracingMiddleware(options = {}) {
1032
+ return async (req, next) => {
1033
+ const method = req.method;
1034
+ const url = new URL(req.url);
1035
+ const path = url.pathname;
1036
+ standardMetrics.httpRequests.add(1, { method, path });
1037
+ const startTime = performance.now();
1038
+ return traceAsync(`HTTP ${method} ${path}`, async (span) => {
1039
+ span.setAttribute("http.method", method);
1040
+ span.setAttribute("http.url", req.url);
1041
+ try {
1042
+ const response = await next();
1043
+ span.setAttribute("http.status_code", response.status);
1044
+ const duration = (performance.now() - startTime) / 1000;
1045
+ standardMetrics.httpDuration.record(duration, {
1046
+ method,
1047
+ path,
1048
+ status: response.status.toString()
1049
+ });
1050
+ emitTelemetrySample({
1051
+ req,
1052
+ res: response,
1053
+ span,
1054
+ success: true,
1055
+ durationMs: duration * 1000,
1056
+ options
1057
+ });
1058
+ return response;
1059
+ } catch (error) {
1060
+ standardMetrics.operationErrors.add(1, { method, path });
1061
+ emitTelemetrySample({
1062
+ req,
1063
+ span,
1064
+ success: false,
1065
+ durationMs: performance.now() - startTime,
1066
+ error,
1067
+ options
1068
+ });
1069
+ throw error;
1070
+ }
1071
+ });
1072
+ };
1073
+ }
1074
+ function emitTelemetrySample({
1075
+ req,
1076
+ res,
1077
+ span,
1078
+ success,
1079
+ durationMs,
1080
+ error,
1081
+ options
1082
+ }) {
1083
+ if (!options.onSample || !options.resolveOperation)
1084
+ return;
1085
+ const operation = options.resolveOperation({ req, res });
1086
+ if (!operation)
1087
+ return;
1088
+ const sample = {
1089
+ operation,
1090
+ durationMs,
1091
+ success,
1092
+ timestamp: new Date,
1093
+ errorCode: !success && error instanceof Error ? error.name : success ? undefined : "unknown",
1094
+ tenantId: options.tenantResolver?.(req),
1095
+ actorId: options.actorResolver?.(req),
1096
+ traceId: span.spanContext().traceId,
1097
+ metadata: {
1098
+ method: req.method,
1099
+ path: new URL(req.url).pathname,
1100
+ status: res?.status
1101
+ }
1102
+ };
1103
+ options.onSample(sample);
1104
+ }
1105
1105
  export {
1106
1106
  traceSync,
1107
1107
  traceModelSelection,
@@ -1,6 +1,6 @@
1
1
  // @bun
2
2
  // src/logging/index.ts
3
- import { trace, context } from "@opentelemetry/api";
3
+ import { context, trace } from "@opentelemetry/api";
4
4
 
5
5
  class Logger {
6
6
  serviceName;
@@ -1,4 +1,4 @@
1
- import { type Meter, type Counter, type Histogram, type UpDownCounter } from '@opentelemetry/api';
1
+ import { type Counter, type Histogram, type Meter, type UpDownCounter } from '@opentelemetry/api';
2
2
  export declare function getMeter(name?: string): Meter;
3
3
  export declare function createCounter(name: string, description?: string, meterName?: string): Counter;
4
4
  export declare function createUpDownCounter(name: string, description?: string, meterName?: string): UpDownCounter;