@zudojs/observability 0.1.0 → 1.0.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.
Files changed (157) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +260 -13
  3. package/dist/errors/index.d.ts +5 -0
  4. package/dist/errors/index.js +5 -0
  5. package/dist/errors/observabilityError.core.d.ts +32 -0
  6. package/dist/errors/observabilityError.core.js +56 -0
  7. package/dist/exporter/exporter.console.d.ts +51 -3
  8. package/dist/exporter/exporter.console.js +110 -23
  9. package/dist/exporter/index.d.ts +2 -2
  10. package/dist/exporter/index.js +2 -2
  11. package/dist/index.d.ts +17 -11
  12. package/dist/index.js +20 -12
  13. package/dist/internal/ids.core.d.ts +26 -0
  14. package/dist/internal/ids.core.js +51 -0
  15. package/dist/internal/index.d.ts +5 -0
  16. package/dist/internal/index.js +5 -0
  17. package/dist/logLevel/index.d.ts +1 -1
  18. package/dist/logLevel/index.js +1 -1
  19. package/dist/logLevel/logLevel.type.d.ts +8 -2
  20. package/dist/logLevel/logLevel.type.js +27 -20
  21. package/dist/logRecord/index.d.ts +1 -1
  22. package/dist/logRecord/index.js +1 -1
  23. package/dist/logRecord/logRecord.core.d.ts +15 -3
  24. package/dist/logRecord/logRecord.core.js +48 -26
  25. package/dist/logger/logger.core.d.ts +16 -8
  26. package/dist/logger/logger.core.js +54 -23
  27. package/dist/metrics/counter/counter.core.d.ts +4 -1
  28. package/dist/metrics/counter/counter.core.js +11 -3
  29. package/dist/metrics/gauge/gauge.core.d.ts +1 -0
  30. package/dist/metrics/gauge/gauge.core.js +9 -0
  31. package/dist/metrics/histogram/histogram.core.d.ts +22 -11
  32. package/dist/metrics/histogram/histogram.core.js +102 -7
  33. package/dist/metrics/histogram/index.d.ts +1 -1
  34. package/dist/metrics/histogram/index.js +1 -1
  35. package/dist/metrics/index.d.ts +4 -3
  36. package/dist/metrics/index.js +4 -3
  37. package/dist/metrics/metrics.reader.d.ts +39 -0
  38. package/dist/metrics/metrics.reader.js +81 -0
  39. package/dist/metrics/metrics.registry.d.ts +55 -4
  40. package/dist/metrics/metrics.registry.js +136 -49
  41. package/dist/noop/index.d.ts +1 -1
  42. package/dist/noop/index.js +1 -1
  43. package/dist/noop/noopObservability.core.d.ts +14 -2
  44. package/dist/noop/noopObservability.core.js +48 -11
  45. package/dist/observability/observability.core.d.ts +57 -3
  46. package/dist/observability/observability.core.js +206 -50
  47. package/dist/processor/index.d.ts +4 -3
  48. package/dist/processor/index.js +4 -3
  49. package/dist/processor/processor.batch.d.ts +66 -11
  50. package/dist/processor/processor.batch.js +130 -29
  51. package/dist/processor/processor.log.d.ts +56 -0
  52. package/dist/processor/processor.log.js +119 -0
  53. package/dist/propagation/index.d.ts +1 -1
  54. package/dist/propagation/index.js +1 -1
  55. package/dist/propagation/propagation.core.d.ts +26 -6
  56. package/dist/propagation/propagation.core.js +35 -19
  57. package/dist/redaction/index.d.ts +1 -1
  58. package/dist/redaction/index.js +1 -1
  59. package/dist/redaction/redaction.core.d.ts +37 -5
  60. package/dist/redaction/redaction.core.js +180 -36
  61. package/dist/sampling/index.d.ts +1 -1
  62. package/dist/sampling/index.js +1 -1
  63. package/dist/sampling/sampler.type.d.ts +38 -6
  64. package/dist/sampling/sampler.type.js +64 -23
  65. package/dist/tracing/index.d.ts +2 -2
  66. package/dist/tracing/index.js +2 -2
  67. package/dist/tracing/span/index.d.ts +1 -1
  68. package/dist/tracing/span/index.js +1 -1
  69. package/dist/tracing/span/span.core.d.ts +51 -8
  70. package/dist/tracing/span/span.core.js +90 -10
  71. package/dist/tracing/span/spanContext.type.d.ts +12 -3
  72. package/dist/tracing/span/spanContext.type.js +19 -16
  73. package/dist/tracing/tracer/index.d.ts +2 -2
  74. package/dist/tracing/tracer/index.js +2 -2
  75. package/dist/tracing/tracer/tracer.core.d.ts +44 -14
  76. package/dist/tracing/tracer/tracer.core.js +81 -25
  77. package/dist/types/config.types.d.ts +138 -0
  78. package/dist/types/config.types.js +5 -0
  79. package/dist/types/logging.types.d.ts +94 -0
  80. package/dist/types/logging.types.js +20 -0
  81. package/dist/types/metrics.types.d.ts +93 -0
  82. package/dist/types/metrics.types.js +5 -0
  83. package/dist/types/tracing.types.d.ts +115 -0
  84. package/dist/types/tracing.types.js +28 -0
  85. package/package.json +23 -14
  86. package/dist/exporter/exporter.console.d.ts.map +0 -1
  87. package/dist/exporter/exporter.console.js.map +0 -1
  88. package/dist/exporter/index.d.ts.map +0 -1
  89. package/dist/exporter/index.js.map +0 -1
  90. package/dist/index.d.ts.map +0 -1
  91. package/dist/index.js.map +0 -1
  92. package/dist/logLevel/index.d.ts.map +0 -1
  93. package/dist/logLevel/index.js.map +0 -1
  94. package/dist/logLevel/logLevel.type.d.ts.map +0 -1
  95. package/dist/logLevel/logLevel.type.js.map +0 -1
  96. package/dist/logRecord/index.d.ts.map +0 -1
  97. package/dist/logRecord/index.js.map +0 -1
  98. package/dist/logRecord/logRecord.core.d.ts.map +0 -1
  99. package/dist/logRecord/logRecord.core.js.map +0 -1
  100. package/dist/logger/index.d.ts.map +0 -1
  101. package/dist/logger/index.js.map +0 -1
  102. package/dist/logger/logger.core.d.ts.map +0 -1
  103. package/dist/logger/logger.core.js.map +0 -1
  104. package/dist/metrics/counter/counter.core.d.ts.map +0 -1
  105. package/dist/metrics/counter/counter.core.js.map +0 -1
  106. package/dist/metrics/counter/index.d.ts.map +0 -1
  107. package/dist/metrics/counter/index.js.map +0 -1
  108. package/dist/metrics/gauge/gauge.core.d.ts.map +0 -1
  109. package/dist/metrics/gauge/gauge.core.js.map +0 -1
  110. package/dist/metrics/gauge/index.d.ts.map +0 -1
  111. package/dist/metrics/gauge/index.js.map +0 -1
  112. package/dist/metrics/histogram/histogram.core.d.ts.map +0 -1
  113. package/dist/metrics/histogram/histogram.core.js.map +0 -1
  114. package/dist/metrics/histogram/index.d.ts.map +0 -1
  115. package/dist/metrics/histogram/index.js.map +0 -1
  116. package/dist/metrics/index.d.ts.map +0 -1
  117. package/dist/metrics/index.js.map +0 -1
  118. package/dist/metrics/metrics.registry.d.ts.map +0 -1
  119. package/dist/metrics/metrics.registry.js.map +0 -1
  120. package/dist/noop/index.d.ts.map +0 -1
  121. package/dist/noop/index.js.map +0 -1
  122. package/dist/noop/noopObservability.core.d.ts.map +0 -1
  123. package/dist/noop/noopObservability.core.js.map +0 -1
  124. package/dist/observability/index.d.ts.map +0 -1
  125. package/dist/observability/index.js.map +0 -1
  126. package/dist/observability/observability.core.d.ts.map +0 -1
  127. package/dist/observability/observability.core.js.map +0 -1
  128. package/dist/processor/index.d.ts.map +0 -1
  129. package/dist/processor/index.js.map +0 -1
  130. package/dist/processor/processor.batch.d.ts.map +0 -1
  131. package/dist/processor/processor.batch.js.map +0 -1
  132. package/dist/propagation/index.d.ts.map +0 -1
  133. package/dist/propagation/index.js.map +0 -1
  134. package/dist/propagation/propagation.core.d.ts.map +0 -1
  135. package/dist/propagation/propagation.core.js.map +0 -1
  136. package/dist/redaction/index.d.ts.map +0 -1
  137. package/dist/redaction/index.js.map +0 -1
  138. package/dist/redaction/redaction.core.d.ts.map +0 -1
  139. package/dist/redaction/redaction.core.js.map +0 -1
  140. package/dist/sampling/index.d.ts.map +0 -1
  141. package/dist/sampling/index.js.map +0 -1
  142. package/dist/sampling/sampler.type.d.ts.map +0 -1
  143. package/dist/sampling/sampler.type.js.map +0 -1
  144. package/dist/tracing/index.d.ts.map +0 -1
  145. package/dist/tracing/index.js.map +0 -1
  146. package/dist/tracing/span/index.d.ts.map +0 -1
  147. package/dist/tracing/span/index.js.map +0 -1
  148. package/dist/tracing/span/span.core.d.ts.map +0 -1
  149. package/dist/tracing/span/span.core.js.map +0 -1
  150. package/dist/tracing/span/spanContext.type.d.ts.map +0 -1
  151. package/dist/tracing/span/spanContext.type.js.map +0 -1
  152. package/dist/tracing/tracer/index.d.ts.map +0 -1
  153. package/dist/tracing/tracer/index.js.map +0 -1
  154. package/dist/tracing/tracer/tracer.core.d.ts.map +0 -1
  155. package/dist/tracing/tracer/tracer.core.js.map +0 -1
  156. package/dist/types.d.ts.map +0 -1
  157. package/dist/types.js.map +0 -1
@@ -2,14 +2,73 @@
2
2
  * @zudojs/observability — Console Exporter
3
3
  *
4
4
  * Exports telemetry to the console for development and debugging.
5
+ *
6
+ * Serialization is defensive, because everything here is fed values the API
7
+ * declares as `unknown`: circular structures, BigInts and throwing getters all
8
+ * reach `JSON.stringify` eventually, and an exporter that throws inside the
9
+ * logging path takes the process with it.
5
10
  */
11
+ import { LogLevel } from "../types.js";
12
+ /**
13
+ * JSON.stringify that cannot throw.
14
+ *
15
+ * Cycles become `"[Circular]"`, BigInts become their decimal string, and a
16
+ * value that defeats serialization entirely falls back to `String(value)`.
17
+ *
18
+ * "Cycle" means an ancestor, not "seen before". A `WeakSet` of every object
19
+ * already visited also matches a value referenced twice from different
20
+ * branches — `{ user, actor: user }` — and silently replaced the second copy
21
+ * with `[Circular]`, losing real telemetry that was never circular. The
22
+ * replacer's `this` is the object currently being serialized, which is what
23
+ * lets the ancestor chain be tracked exactly.
24
+ */
25
+ export function safeStringify(value, pretty = false) {
26
+ const ancestors = [];
27
+ try {
28
+ return (JSON.stringify(value, function replacer(_key, entry) {
29
+ // Unwind to the holder of the value being visited.
30
+ while (ancestors.length > 0 &&
31
+ ancestors[ancestors.length - 1] !== this) {
32
+ ancestors.pop();
33
+ }
34
+ if (typeof entry === "bigint")
35
+ return entry.toString();
36
+ if (typeof entry === "function")
37
+ return "[Function]";
38
+ if (typeof entry === "symbol")
39
+ return entry.toString();
40
+ if (entry instanceof Error) {
41
+ return {
42
+ name: entry.name,
43
+ message: entry.message,
44
+ stack: entry.stack,
45
+ };
46
+ }
47
+ if (typeof entry === "object" && entry !== null) {
48
+ if (ancestors.includes(entry))
49
+ return "[Circular]";
50
+ ancestors.push(entry);
51
+ }
52
+ return entry;
53
+ }, pretty ? 2 : undefined) ?? String(value));
54
+ }
55
+ catch {
56
+ return String(value);
57
+ }
58
+ }
6
59
  /**
7
60
  * Exports completed spans to the console.
8
61
  */
9
62
  export class ConsoleSpanExporter {
63
+ pretty;
64
+ out;
65
+ constructor(options) {
66
+ this.pretty = options?.pretty ?? false;
67
+ this.out = options?.console ?? console;
68
+ }
10
69
  async export(spans) {
11
70
  for (const span of spans) {
12
- console.log(JSON.stringify({
71
+ this.out.log(safeStringify({
13
72
  type: "span",
14
73
  name: span.name,
15
74
  traceId: span.context.traceId,
@@ -17,13 +76,20 @@ export class ConsoleSpanExporter {
17
76
  parentSpanId: span.context.parentSpanId,
18
77
  kind: span.kind,
19
78
  status: span.status,
20
- duration: `${span.duration}ms`,
79
+ statusMessage: span.statusMessage,
80
+ durationMs: span.duration,
21
81
  startTime: span.startTime.toISOString(),
22
82
  endTime: span.endTime.toISOString(),
23
83
  attributes: span.attributes,
24
84
  events: span.events,
25
85
  resource: span.resource,
26
- }, null, 2));
86
+ ...(span.droppedAttributes > 0
87
+ ? { droppedAttributes: span.droppedAttributes }
88
+ : {}),
89
+ ...(span.droppedEvents > 0
90
+ ? { droppedEvents: span.droppedEvents }
91
+ : {}),
92
+ }, this.pretty));
27
93
  }
28
94
  }
29
95
  async shutdown() {
@@ -34,25 +100,30 @@ export class ConsoleSpanExporter {
34
100
  * Exports log records to the console.
35
101
  */
36
102
  export class ConsoleLogExporter {
103
+ pretty;
104
+ out;
105
+ constructor(options) {
106
+ this.pretty = options?.pretty ?? false;
107
+ this.out = options?.console ?? console;
108
+ }
37
109
  async export(records) {
38
110
  for (const record of records) {
39
- const output = {
111
+ const line = safeStringify({
40
112
  timestamp: record.timestamp.toISOString(),
41
113
  level: record.levelName,
42
114
  logger: record.loggerName,
43
115
  message: record.message,
116
+ ...(record.traceId ? { traceId: record.traceId } : {}),
117
+ ...(record.spanId ? { spanId: record.spanId } : {}),
44
118
  ...(record.context ? { context: record.context } : {}),
45
119
  ...(record.error ? { error: record.error } : {}),
46
- };
47
- if (record.level >= 4) {
48
- console.error(JSON.stringify(output, null, 2));
49
- }
50
- else if (record.level >= 3) {
51
- console.warn(JSON.stringify(output, null, 2));
52
- }
53
- else {
54
- console.log(JSON.stringify(output, null, 2));
55
- }
120
+ }, this.pretty);
121
+ if (record.level >= LogLevel.ERROR)
122
+ this.out.error(line);
123
+ else if (record.level >= LogLevel.WARN)
124
+ this.out.warn(line);
125
+ else
126
+ this.out.log(line);
56
127
  }
57
128
  }
58
129
  async shutdown() {
@@ -63,32 +134,48 @@ export class ConsoleLogExporter {
63
134
  * Exports metric snapshots to the console.
64
135
  */
65
136
  export class ConsoleMetricExporter {
137
+ pretty;
138
+ out;
139
+ constructor(options) {
140
+ this.pretty = options?.pretty ?? false;
141
+ this.out = options?.console ?? console;
142
+ }
66
143
  async export(snapshots) {
67
144
  for (const snapshot of snapshots) {
68
- console.log(JSON.stringify({
145
+ this.out.log(safeStringify({
69
146
  type: "metric",
70
147
  metricType: snapshot.type,
71
148
  name: snapshot.name,
72
149
  value: snapshot.value,
73
150
  labels: snapshot.labels,
74
- timestamp: new Date().toISOString(),
75
- }, null, 2));
151
+ timestamp: snapshot.timestamp.toISOString(),
152
+ }, this.pretty));
76
153
  }
77
154
  }
78
155
  async shutdown() {
79
156
  // No resources to clean up
80
157
  }
81
158
  }
159
+ /** A log exporter that discards everything. */
160
+ export const noopLogExporter = {
161
+ export: async () => { },
162
+ shutdown: async () => { },
163
+ };
164
+ /** A metric exporter that discards everything. */
165
+ export const noopMetricExporter = {
166
+ export: async () => { },
167
+ shutdown: async () => { },
168
+ };
82
169
  /** Creates a console span exporter. */
83
- export function createConsoleSpanExporter() {
84
- return new ConsoleSpanExporter();
170
+ export function createConsoleSpanExporter(options) {
171
+ return new ConsoleSpanExporter(options);
85
172
  }
86
173
  /** Creates a console log exporter. */
87
- export function createConsoleLogExporter() {
88
- return new ConsoleLogExporter();
174
+ export function createConsoleLogExporter(options) {
175
+ return new ConsoleLogExporter(options);
89
176
  }
90
177
  /** Creates a console metric exporter. */
91
- export function createConsoleMetricExporter() {
92
- return new ConsoleMetricExporter();
178
+ export function createConsoleMetricExporter(options) {
179
+ return new ConsoleMetricExporter(options);
93
180
  }
94
181
  //# sourceMappingURL=exporter.console.js.map
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * @zudojs/observability — Exporters
3
3
  *
4
- * Console exporters for spans, logs, and metrics.
4
+ * Console exporters for spans, logs, and metrics, plus no-op exporters.
5
5
  */
6
- export { ConsoleSpanExporter, ConsoleLogExporter, ConsoleMetricExporter, createConsoleSpanExporter, createConsoleLogExporter, createConsoleMetricExporter, } from "./exporter.console.js";
6
+ export { ConsoleSpanExporter, ConsoleLogExporter, ConsoleMetricExporter, createConsoleSpanExporter, createConsoleLogExporter, createConsoleMetricExporter, noopLogExporter, noopMetricExporter, safeStringify, type ConsoleExporterOptions, type ConsoleLike, } from "./exporter.console.js";
7
7
  //# sourceMappingURL=index.d.ts.map
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * @zudojs/observability — Exporters
3
3
  *
4
- * Console exporters for spans, logs, and metrics.
4
+ * Console exporters for spans, logs, and metrics, plus no-op exporters.
5
5
  */
6
- export { ConsoleSpanExporter, ConsoleLogExporter, ConsoleMetricExporter, createConsoleSpanExporter, createConsoleLogExporter, createConsoleMetricExporter, } from "./exporter.console.js";
6
+ export { ConsoleSpanExporter, ConsoleLogExporter, ConsoleMetricExporter, createConsoleSpanExporter, createConsoleLogExporter, createConsoleMetricExporter, noopLogExporter, noopMetricExporter, safeStringify, } from "./exporter.console.js";
7
7
  //# sourceMappingURL=index.js.map
package/dist/index.d.ts CHANGED
@@ -16,27 +16,33 @@
16
16
  * const obs = createObservability({
17
17
  * serviceName: "my-api",
18
18
  * logLevel: LogLevel.INFO,
19
+ * redaction: {}, // opt in to redaction
20
+ * sampler: createProbabilitySampler(0.1),
19
21
  * });
20
22
  *
21
23
  * obs.logger.info("Server started", { port: 3000 });
22
24
  * obs.metrics.counter("http.requests.total").increment();
23
25
  * const span = obs.tracer.startSpan("handle-request");
24
26
  * span.end();
27
+ *
28
+ * await obs.shutdown();
25
29
  * ```
26
30
  *
27
31
  * @packageDocumentation
28
32
  */
29
- export { LogLevel, SpanStatus, SpanKind, type LogLevelName, type LogRecord, type Logger, type LoggerOptions, type LogTransport, type PropagationContext, type PropagationContextOptions, type PropagationManager, type Counter, type Gauge, type Histogram, type MetricsRegistry, type MetricSnapshot, type Span, type SpanContext, type SpanEvent, type SpanOptions, type Tracer, type ReadableSpan, type SpanExporter, type LogExporter, type MetricExporter, type SpanProcessor, type SamplingResult, type Sampler, type RedactionConfig, type Observability, type ObservabilityConfig, } from "./types.js";
30
- export { logLevelToName, logLevelFromName, shouldLog, getLogLevelNames, } from "./logLevel/index.js";
31
- export { createLogRecord, createErrorLogRecord } from "./logRecord/index.js";
33
+ export { LogLevel, SpanStatus, SpanKind, TraceFlags, type LogLevelName, type LogRecord, type LogRecordError, type Logger, type LoggerOptions, type LogTransport, type PropagationContext, type PropagationContextOptions, type PropagationManager, type Counter, type Gauge, type Histogram, type HistogramValue, type MetricsRegistry, type MetricSnapshot, type Span, type SpanContext, type SpanEvent, type SpanOptions, type SpanLimits, type Tracer, type ReadableSpan, type SpanExporter, type LogExporter, type MetricExporter, type SpanProcessor, type SamplingResult, type Sampler, type RedactionConfig, type RedactionMatchMode, type Observability, type ObservabilityConfig, } from "./types.js";
34
+ export { ObservabilityError, ExporterError, ObservabilityConfigError, MetricValueError, isObservabilityError, } from "./errors/index.js";
35
+ export { generateTraceId, generateSpanId, isValidTraceId, isValidSpanId, } from "./internal/index.js";
36
+ export { logLevelToName, logLevelFromName, parseLogLevel, shouldLog, getLogLevelNames, } from "./logLevel/index.js";
37
+ export { createLogRecord, createErrorLogRecord, serializeError, } from "./logRecord/index.js";
32
38
  export { StructuredLogger, createStructuredLogger } from "./logger/index.js";
33
- export { createPropagationContext, derivePropagationContext, getCurrentContext, AsyncPropagationManager, createPropagationManager, } from "./propagation/index.js";
34
- export { DefaultCounter, createCounter, DefaultGauge, createGauge, DefaultHistogram, createHistogram, DefaultMetricsRegistry, createMetricsRegistry, } from "./metrics/index.js";
35
- export { DefaultSpan, createSpan, createSpanContext, createChildSpanContext, DefaultTracer, createTracer, } from "./tracing/index.js";
36
- export { AlwaysOnSampler, AlwaysOffSampler, ProbabilitySampler, ParentBasedSampler, createAlwaysOnSampler, createAlwaysOffSampler, createProbabilitySampler, createParentBasedSampler, } from "./sampling/index.js";
37
- export { ConsoleSpanExporter, ConsoleLogExporter, ConsoleMetricExporter, createConsoleSpanExporter, createConsoleLogExporter, createConsoleMetricExporter, } from "./exporter/index.js";
38
- export { BatchSpanProcessor, createBatchSpanProcessor, } from "./processor/index.js";
39
- export { createRedactor, redactObject, isSensitiveField, } from "./redaction/index.js";
40
- export { NoopObservability, createNoopObservability, noopLogger, noopCounter, noopGauge, noopHistogram, noopMetricsRegistry, noopSpan, noopTracer, noopPropagationManager, } from "./noop/index.js";
39
+ export { createPropagationContext, derivePropagationContext, getCurrentContext, requireCurrentContext, AsyncPropagationManager, createPropagationManager, } from "./propagation/index.js";
40
+ export { DefaultCounter, createCounter, DefaultGauge, createGauge, DefaultHistogram, createHistogram, DEFAULT_BUCKET_BOUNDARIES, DefaultMetricsRegistry, createMetricsRegistry, metricKey, PeriodicMetricReader, createPeriodicMetricReader, type MetricsRegistryOptions, type PeriodicMetricReaderOptions, } from "./metrics/index.js";
41
+ export { DefaultSpan, createSpan, createSpanContext, createChildSpanContext, isSampledContext, DefaultTracer, createTracer, type TracerOptions, } from "./tracing/index.js";
42
+ export { AlwaysOnSampler, AlwaysOffSampler, ProbabilitySampler, ParentBasedSampler, createAlwaysOnSampler, createAlwaysOffSampler, createProbabilitySampler, createParentBasedSampler, isSampled, isRecording, type ParentBasedSamplerOptions, } from "./sampling/index.js";
43
+ export { ConsoleSpanExporter, ConsoleLogExporter, ConsoleMetricExporter, createConsoleSpanExporter, createConsoleLogExporter, createConsoleMetricExporter, noopLogExporter, noopMetricExporter, safeStringify, type ConsoleExporterOptions, type ConsoleLike, } from "./exporter/index.js";
44
+ export { BatchSpanProcessor, createBatchSpanProcessor, SimpleSpanProcessor, createSimpleSpanProcessor, BatchLogProcessor, createBatchLogProcessor, noopSpanExporter, type BatchSpanProcessorOptions, type BatchLogProcessorOptions, } from "./processor/index.js";
45
+ export { createRedactor, createStructureRedactor, redactObject, redactValue, isSensitiveField, DEFAULT_SENSITIVE_FIELDS, CIRCULAR_MARKER, MAX_DEPTH_MARKER, } from "./redaction/index.js";
46
+ export { NoopObservability, createNoopObservability, noopLogger, noopCounter, noopGauge, noopHistogram, noopMetricsRegistry, noopSpan, noopTracer, noopPropagationManager, INVALID_PROPAGATION_CONTEXT, } from "./noop/index.js";
41
47
  export { DefaultObservability, createObservability, } from "./observability/index.js";
42
48
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -16,40 +16,48 @@
16
16
  * const obs = createObservability({
17
17
  * serviceName: "my-api",
18
18
  * logLevel: LogLevel.INFO,
19
+ * redaction: {}, // opt in to redaction
20
+ * sampler: createProbabilitySampler(0.1),
19
21
  * });
20
22
  *
21
23
  * obs.logger.info("Server started", { port: 3000 });
22
24
  * obs.metrics.counter("http.requests.total").increment();
23
25
  * const span = obs.tracer.startSpan("handle-request");
24
26
  * span.end();
27
+ *
28
+ * await obs.shutdown();
25
29
  * ```
26
30
  *
27
31
  * @packageDocumentation
28
32
  */
29
33
  /* ─── Core Types ────────────────────────────────────────────────────────── */
30
- export { LogLevel, SpanStatus, SpanKind, } from "./types.js";
34
+ export { LogLevel, SpanStatus, SpanKind, TraceFlags, } from "./types.js";
35
+ /* ─── Errors ────────────────────────────────────────────────────────────── */
36
+ export { ObservabilityError, ExporterError, ObservabilityConfigError, MetricValueError, isObservabilityError, } from "./errors/index.js";
37
+ /* ─── Identifiers ───────────────────────────────────────────────────────── */
38
+ export { generateTraceId, generateSpanId, isValidTraceId, isValidSpanId, } from "./internal/index.js";
31
39
  /* ─── Log Level ─────────────────────────────────────────────────────────── */
32
- export { logLevelToName, logLevelFromName, shouldLog, getLogLevelNames, } from "./logLevel/index.js";
40
+ export { logLevelToName, logLevelFromName, parseLogLevel, shouldLog, getLogLevelNames, } from "./logLevel/index.js";
33
41
  /* ─── Log Record ────────────────────────────────────────────────────────── */
34
- export { createLogRecord, createErrorLogRecord } from "./logRecord/index.js";
42
+ export { createLogRecord, createErrorLogRecord, serializeError, } from "./logRecord/index.js";
35
43
  /* ─── Logger ────────────────────────────────────────────────────────────── */
36
44
  export { StructuredLogger, createStructuredLogger } from "./logger/index.js";
37
45
  /* ─── Propagation ───────────────────────────────────────────────────────── */
38
- export { createPropagationContext, derivePropagationContext, getCurrentContext, AsyncPropagationManager, createPropagationManager, } from "./propagation/index.js";
46
+ export { createPropagationContext, derivePropagationContext, getCurrentContext, requireCurrentContext, AsyncPropagationManager, createPropagationManager, } from "./propagation/index.js";
39
47
  /* ─── Metrics ───────────────────────────────────────────────────────────── */
40
- export { DefaultCounter, createCounter, DefaultGauge, createGauge, DefaultHistogram, createHistogram, DefaultMetricsRegistry, createMetricsRegistry, } from "./metrics/index.js";
48
+ export { DefaultCounter, createCounter, DefaultGauge, createGauge, DefaultHistogram, createHistogram, DEFAULT_BUCKET_BOUNDARIES, DefaultMetricsRegistry, createMetricsRegistry, metricKey, PeriodicMetricReader, createPeriodicMetricReader, } from "./metrics/index.js";
41
49
  /* ─── Tracing ───────────────────────────────────────────────────────────── */
42
- export { DefaultSpan, createSpan, createSpanContext, createChildSpanContext, DefaultTracer, createTracer, } from "./tracing/index.js";
50
+ export { DefaultSpan, createSpan, createSpanContext, createChildSpanContext, isSampledContext, DefaultTracer, createTracer, } from "./tracing/index.js";
43
51
  /* ─── Sampling ──────────────────────────────────────────────────────────── */
44
- export { AlwaysOnSampler, AlwaysOffSampler, ProbabilitySampler, ParentBasedSampler, createAlwaysOnSampler, createAlwaysOffSampler, createProbabilitySampler, createParentBasedSampler, } from "./sampling/index.js";
52
+ export { AlwaysOnSampler, AlwaysOffSampler, ProbabilitySampler, ParentBasedSampler, createAlwaysOnSampler, createAlwaysOffSampler, createProbabilitySampler, createParentBasedSampler, isSampled, isRecording, } from "./sampling/index.js";
45
53
  /* ─── Exporters ─────────────────────────────────────────────────────────── */
46
- export { ConsoleSpanExporter, ConsoleLogExporter, ConsoleMetricExporter, createConsoleSpanExporter, createConsoleLogExporter, createConsoleMetricExporter, } from "./exporter/index.js";
47
- /* ─── Processor ─────────────────────────────────────────────────────────── */
48
- export { BatchSpanProcessor, createBatchSpanProcessor, } from "./processor/index.js";
54
+ export { ConsoleSpanExporter, ConsoleLogExporter, ConsoleMetricExporter, createConsoleSpanExporter, createConsoleLogExporter, createConsoleMetricExporter, noopLogExporter, noopMetricExporter, safeStringify, } from "./exporter/index.js";
55
+ /* ─── Processors ────────────────────────────────────────────────────────── */
56
+ export { BatchSpanProcessor, createBatchSpanProcessor, SimpleSpanProcessor, createSimpleSpanProcessor, BatchLogProcessor, createBatchLogProcessor, noopSpanExporter, } from "./processor/index.js";
49
57
  /* ─── Redaction ─────────────────────────────────────────────────────────── */
50
- export { createRedactor, redactObject, isSensitiveField, } from "./redaction/index.js";
58
+ export { createRedactor, createStructureRedactor, redactObject, redactValue, isSensitiveField, DEFAULT_SENSITIVE_FIELDS, CIRCULAR_MARKER, MAX_DEPTH_MARKER, } from "./redaction/index.js";
51
59
  /* ─── Noop ──────────────────────────────────────────────────────────────── */
52
- export { NoopObservability, createNoopObservability, noopLogger, noopCounter, noopGauge, noopHistogram, noopMetricsRegistry, noopSpan, noopTracer, noopPropagationManager, } from "./noop/index.js";
60
+ export { NoopObservability, createNoopObservability, noopLogger, noopCounter, noopGauge, noopHistogram, noopMetricsRegistry, noopSpan, noopTracer, noopPropagationManager, INVALID_PROPAGATION_CONTEXT, } from "./noop/index.js";
53
61
  /* ─── Observability Facade ──────────────────────────────────────────────── */
54
62
  export { DefaultObservability, createObservability, } from "./observability/index.js";
55
63
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @zudojs/observability — Identifier generation
3
+ *
4
+ * One generator, used by both the propagation context and the span context.
5
+ * IDs come from `node:crypto`, not `Math.random()`: trace, span, request and
6
+ * correlation IDs routinely end up in idempotency keys, log correlation and
7
+ * access decisions, and a predictable stream of them is a liability that a
8
+ * CSPRNG costs nothing to avoid.
9
+ */
10
+ /** Bytes in a W3C trace ID. */
11
+ export declare const TRACE_ID_BYTES = 16;
12
+ /** Bytes in a W3C span ID. */
13
+ export declare const SPAN_ID_BYTES = 8;
14
+ /** Generates a cryptographically random lowercase hex ID. */
15
+ export declare function generateHexId(byteLength: number): string;
16
+ /** Generates a 16-byte trace ID, never the all-zero (invalid) value. */
17
+ export declare function generateTraceId(): string;
18
+ /** Generates an 8-byte span ID, never the all-zero (invalid) value. */
19
+ export declare function generateSpanId(): string;
20
+ /** True when `id` is valid lowercase hex of the expected width and non-zero. */
21
+ export declare function isValidId(id: string, byteLength: number): boolean;
22
+ /** True when `traceId` is a valid W3C trace ID. */
23
+ export declare function isValidTraceId(traceId: string): boolean;
24
+ /** True when `spanId` is a valid W3C span ID. */
25
+ export declare function isValidSpanId(spanId: string): boolean;
26
+ //# sourceMappingURL=ids.core.d.ts.map
@@ -0,0 +1,51 @@
1
+ /**
2
+ * @zudojs/observability — Identifier generation
3
+ *
4
+ * One generator, used by both the propagation context and the span context.
5
+ * IDs come from `node:crypto`, not `Math.random()`: trace, span, request and
6
+ * correlation IDs routinely end up in idempotency keys, log correlation and
7
+ * access decisions, and a predictable stream of them is a liability that a
8
+ * CSPRNG costs nothing to avoid.
9
+ */
10
+ import { randomBytes } from "node:crypto";
11
+ /** Bytes in a W3C trace ID. */
12
+ export const TRACE_ID_BYTES = 16;
13
+ /** Bytes in a W3C span ID. */
14
+ export const SPAN_ID_BYTES = 8;
15
+ const INVALID_TRACE_ID = "0".repeat(TRACE_ID_BYTES * 2);
16
+ const INVALID_SPAN_ID = "0".repeat(SPAN_ID_BYTES * 2);
17
+ /** Generates a cryptographically random lowercase hex ID. */
18
+ export function generateHexId(byteLength) {
19
+ return randomBytes(byteLength).toString("hex");
20
+ }
21
+ /** Generates a 16-byte trace ID, never the all-zero (invalid) value. */
22
+ export function generateTraceId() {
23
+ let id = generateHexId(TRACE_ID_BYTES);
24
+ while (id === INVALID_TRACE_ID)
25
+ id = generateHexId(TRACE_ID_BYTES);
26
+ return id;
27
+ }
28
+ /** Generates an 8-byte span ID, never the all-zero (invalid) value. */
29
+ export function generateSpanId() {
30
+ let id = generateHexId(SPAN_ID_BYTES);
31
+ while (id === INVALID_SPAN_ID)
32
+ id = generateHexId(SPAN_ID_BYTES);
33
+ return id;
34
+ }
35
+ /** True when `id` is valid lowercase hex of the expected width and non-zero. */
36
+ export function isValidId(id, byteLength) {
37
+ if (id.length !== byteLength * 2)
38
+ return false;
39
+ if (!/^[0-9a-f]+$/.test(id))
40
+ return false;
41
+ return !/^0+$/.test(id);
42
+ }
43
+ /** True when `traceId` is a valid W3C trace ID. */
44
+ export function isValidTraceId(traceId) {
45
+ return isValidId(traceId, TRACE_ID_BYTES);
46
+ }
47
+ /** True when `spanId` is a valid W3C span ID. */
48
+ export function isValidSpanId(spanId) {
49
+ return isValidId(spanId, SPAN_ID_BYTES);
50
+ }
51
+ //# sourceMappingURL=ids.core.js.map
@@ -0,0 +1,5 @@
1
+ /**
2
+ * @zudojs/observability — Internal helpers shared across modules.
3
+ */
4
+ export { generateHexId, generateTraceId, generateSpanId, isValidId, isValidTraceId, isValidSpanId, TRACE_ID_BYTES, SPAN_ID_BYTES, } from "./ids.core.js";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,5 @@
1
+ /**
2
+ * @zudojs/observability — Internal helpers shared across modules.
3
+ */
4
+ export { generateHexId, generateTraceId, generateSpanId, isValidId, isValidTraceId, isValidSpanId, TRACE_ID_BYTES, SPAN_ID_BYTES, } from "./ids.core.js";
5
+ //# sourceMappingURL=index.js.map
@@ -3,5 +3,5 @@
3
3
  *
4
4
  * Level names, conversion, and filtering utilities.
5
5
  */
6
- export { logLevelToName, logLevelFromName, shouldLog, getLogLevelNames, } from "./logLevel.type.js";
6
+ export { logLevelToName, logLevelFromName, parseLogLevel, shouldLog, getLogLevelNames, } from "./logLevel.type.js";
7
7
  //# sourceMappingURL=index.d.ts.map
@@ -3,5 +3,5 @@
3
3
  *
4
4
  * Level names, conversion, and filtering utilities.
5
5
  */
6
- export { logLevelToName, logLevelFromName, shouldLog, getLogLevelNames, } from "./logLevel.type.js";
6
+ export { logLevelToName, logLevelFromName, parseLogLevel, shouldLog, getLogLevelNames, } from "./logLevel.type.js";
7
7
  //# sourceMappingURL=index.js.map
@@ -1,14 +1,20 @@
1
1
  /**
2
2
  * @zudojs/observability — Log Level
3
3
  *
4
- * Utility functions for converting between log levels and names,
5
- * and checking whether a message should be logged.
4
+ * The single source of truth for the level↔name mapping, and the filtering
5
+ * predicate every logger uses.
6
6
  */
7
7
  import { LogLevel, type LogLevelName } from "../types.js";
8
8
  /** Converts a numeric level to its name. */
9
9
  export declare function logLevelToName(level: LogLevel): LogLevelName;
10
10
  /** Converts a level name to its numeric value. */
11
11
  export declare function logLevelFromName(name: LogLevelName): LogLevel;
12
+ /**
13
+ * Parses an arbitrary string — an environment variable, a config file entry —
14
+ * into a level, returning `undefined` when it names no level. Use this at a
15
+ * trust boundary; {@link logLevelFromName} assumes the name is already valid.
16
+ */
17
+ export declare function parseLogLevel(value: string): LogLevel | undefined;
12
18
  /** Returns true if a message at `messageLevel` should pass the `threshold`. */
13
19
  export declare function shouldLog(threshold: LogLevel, messageLevel: LogLevel): boolean;
14
20
  /** Returns all log level names. */
@@ -1,38 +1,45 @@
1
1
  /**
2
2
  * @zudojs/observability — Log Level
3
3
  *
4
- * Utility functions for converting between log levels and names,
5
- * and checking whether a message should be logged.
4
+ * The single source of truth for the level↔name mapping, and the filtering
5
+ * predicate every logger uses.
6
6
  */
7
7
  import { LogLevel } from "../types.js";
8
- const LEVEL_NAMES = [
9
- "trace",
10
- "debug",
11
- "info",
12
- "warn",
13
- "error",
14
- "fatal",
15
- "off",
16
- ];
17
- const NAME_TO_LEVEL = new Map([
18
- ["trace", LogLevel.TRACE],
19
- ["debug", LogLevel.DEBUG],
20
- ["info", LogLevel.INFO],
21
- ["warn", LogLevel.WARN],
22
- ["error", LogLevel.ERROR],
23
- ["fatal", LogLevel.FATAL],
24
- ["off", LogLevel.OFF],
8
+ const LEVEL_TO_NAME = new Map([
9
+ [LogLevel.TRACE, "trace"],
10
+ [LogLevel.DEBUG, "debug"],
11
+ [LogLevel.INFO, "info"],
12
+ [LogLevel.WARN, "warn"],
13
+ [LogLevel.ERROR, "error"],
14
+ [LogLevel.FATAL, "fatal"],
15
+ [LogLevel.OFF, "off"],
16
+ ]);
17
+ const NAME_TO_LEVEL = new Map([...LEVEL_TO_NAME].map(([level, name]) => [name, level]));
18
+ // Frozen: this array is handed straight to callers, and an unfrozen module
19
+ // singleton is one `push` away from corrupting every later reader.
20
+ const LEVEL_NAMES = Object.freeze([
21
+ ...LEVEL_TO_NAME.values(),
25
22
  ]);
26
23
  /** Converts a numeric level to its name. */
27
24
  export function logLevelToName(level) {
28
- return LEVEL_NAMES[level] ?? "off";
25
+ return LEVEL_TO_NAME.get(level) ?? "off";
29
26
  }
30
27
  /** Converts a level name to its numeric value. */
31
28
  export function logLevelFromName(name) {
32
29
  return NAME_TO_LEVEL.get(name) ?? LogLevel.OFF;
33
30
  }
31
+ /**
32
+ * Parses an arbitrary string — an environment variable, a config file entry —
33
+ * into a level, returning `undefined` when it names no level. Use this at a
34
+ * trust boundary; {@link logLevelFromName} assumes the name is already valid.
35
+ */
36
+ export function parseLogLevel(value) {
37
+ return NAME_TO_LEVEL.get(value.trim().toLowerCase());
38
+ }
34
39
  /** Returns true if a message at `messageLevel` should pass the `threshold`. */
35
40
  export function shouldLog(threshold, messageLevel) {
41
+ if (threshold >= LogLevel.OFF)
42
+ return false;
36
43
  return messageLevel >= threshold;
37
44
  }
38
45
  /** Returns all log level names. */
@@ -3,5 +3,5 @@
3
3
  *
4
4
  * Structured log record creation and error log records.
5
5
  */
6
- export { createLogRecord, createErrorLogRecord } from "./logRecord.core.js";
6
+ export { createLogRecord, createErrorLogRecord, serializeError, } from "./logRecord.core.js";
7
7
  //# sourceMappingURL=index.d.ts.map
@@ -3,5 +3,5 @@
3
3
  *
4
4
  * Structured log record creation and error log records.
5
5
  */
6
- export { createLogRecord, createErrorLogRecord } from "./logRecord.core.js";
6
+ export { createLogRecord, createErrorLogRecord, serializeError, } from "./logRecord.core.js";
7
7
  //# sourceMappingURL=index.js.map
@@ -3,16 +3,28 @@
3
3
  *
4
4
  * Factory functions for creating structured log records.
5
5
  */
6
- import type { LogRecord } from "../types.js";
6
+ import type { LogRecord, LogRecordError } from "../types.js";
7
7
  import { LogLevel } from "../types.js";
8
+ /**
9
+ * Serializes a thrown value into something a JSON transport can carry.
10
+ *
11
+ * `Error`'s own fields are non-enumerable, so an error placed in a log
12
+ * context stringifies to `{}` — this is what turns it back into data.
13
+ * `cause` chains are followed, with a depth cap so a self-referential cause
14
+ * cannot recurse forever.
15
+ */
16
+ export declare function serializeError(error: unknown, depth?: number): LogRecordError;
8
17
  /** Creates a structured log record. */
9
18
  export declare function createLogRecord(options: {
10
19
  readonly level: LogLevel;
11
20
  readonly message: string;
12
21
  readonly loggerName: string;
13
22
  readonly context?: Record<string, unknown>;
14
- readonly error?: Error;
23
+ readonly error?: unknown;
24
+ readonly traceId?: string;
25
+ readonly spanId?: string;
26
+ readonly timestamp?: Date;
15
27
  }): LogRecord;
16
28
  /** Creates a log record for an error. */
17
- export declare function createErrorLogRecord(error: Error, level: LogLevel, loggerName: string): LogRecord;
29
+ export declare function createErrorLogRecord(error: unknown, level: LogLevel, loggerName: string, context?: Record<string, unknown>): LogRecord;
18
30
  //# sourceMappingURL=logRecord.core.d.ts.map