@effect/opentelemetry 4.0.0-beta.10 → 4.0.0-beta.101

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 (52) hide show
  1. package/dist/NodeSdk.d.ts +86 -14
  2. package/dist/NodeSdk.d.ts.map +1 -1
  3. package/dist/NodeSdk.js +31 -8
  4. package/dist/NodeSdk.js.map +1 -1
  5. package/dist/OtelLogger.d.ts +99 -0
  6. package/dist/OtelLogger.d.ts.map +1 -0
  7. package/dist/OtelLogger.js +139 -0
  8. package/dist/OtelLogger.js.map +1 -0
  9. package/dist/{Metrics.d.ts → OtelMetrics.d.ts} +42 -18
  10. package/dist/OtelMetrics.d.ts.map +1 -0
  11. package/dist/{Metrics.js → OtelMetrics.js} +27 -12
  12. package/dist/OtelMetrics.js.map +1 -0
  13. package/dist/OtelTracer.d.ts +186 -0
  14. package/dist/OtelTracer.d.ts.map +1 -0
  15. package/dist/{Tracer.js → OtelTracer.js} +129 -72
  16. package/dist/OtelTracer.js.map +1 -0
  17. package/dist/Resource.d.ts +57 -13
  18. package/dist/Resource.d.ts.map +1 -1
  19. package/dist/Resource.js +48 -13
  20. package/dist/Resource.js.map +1 -1
  21. package/dist/WebSdk.d.ts +82 -13
  22. package/dist/WebSdk.d.ts.map +1 -1
  23. package/dist/WebSdk.js +28 -7
  24. package/dist/WebSdk.js.map +1 -1
  25. package/dist/index.d.ts +12 -12
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +12 -12
  28. package/dist/index.js.map +1 -1
  29. package/dist/internal/attributes.js +5 -0
  30. package/dist/internal/attributes.js.map +1 -1
  31. package/dist/internal/metrics.js +5 -5
  32. package/dist/internal/metrics.js.map +1 -1
  33. package/package.json +22 -18
  34. package/src/NodeSdk.ts +87 -15
  35. package/src/OtelLogger.ts +193 -0
  36. package/src/{Metrics.ts → OtelMetrics.ts} +42 -18
  37. package/src/{Tracer.ts → OtelTracer.ts} +161 -101
  38. package/src/Resource.ts +58 -14
  39. package/src/WebSdk.ts +83 -14
  40. package/src/index.ts +12 -12
  41. package/src/internal/attributes.ts +7 -0
  42. package/src/internal/metrics.ts +7 -7
  43. package/dist/Logger.d.ts +0 -48
  44. package/dist/Logger.d.ts.map +0 -1
  45. package/dist/Logger.js +0 -76
  46. package/dist/Logger.js.map +0 -1
  47. package/dist/Metrics.d.ts.map +0 -1
  48. package/dist/Metrics.js.map +0 -1
  49. package/dist/Tracer.d.ts +0 -129
  50. package/dist/Tracer.d.ts.map +0 -1
  51. package/dist/Tracer.js.map +0 -1
  52. package/src/Logger.ts +0 -124
@@ -1,18 +1,36 @@
1
1
  /**
2
- * @since 1.0.0
2
+ * Bridges Effect tracing into OpenTelemetry by installing an Effect `Tracer`
3
+ * that creates OpenTelemetry spans, records attributes, events, links, errors,
4
+ * and status, and keeps OpenTelemetry context active while traced effects run.
5
+ * Use this module when an application already has an OpenTelemetry
6
+ * `TracerProvider`, or when the Node and Web SDK layers should expose Effect
7
+ * spans to OTLP, console, or other OpenTelemetry-compatible exporters.
8
+ *
9
+ * The layer constructors wire Effect's tracer service to either the global
10
+ * OpenTelemetry tracer provider or an explicitly provided `OtelTracer`. This
11
+ * module does not create exporters or span processors by itself, so spans are
12
+ * exported only when the provider has been configured by the application or by
13
+ * the Node/Web SDK layers. Parentage is taken from Effect spans first and can
14
+ * also attach to the active OpenTelemetry context, while `makeExternalSpan` and
15
+ * `withSpanContext` are the entry points for continuing an incoming remote
16
+ * trace. Preserve `traceFlags` and `traceState` when building external spans;
17
+ * otherwise sampling defaults to sampled and trace state cannot be propagated.
18
+ *
19
+ * @since 4.0.0
3
20
  */
4
21
  import * as Otel from "@opentelemetry/api"
5
22
  import * as OtelSemConv from "@opentelemetry/semantic-conventions"
6
23
  import * as Cause from "effect/Cause"
7
24
  import type * as Clock from "effect/Clock"
25
+ import * as Context from "effect/Context"
8
26
  import * as Effect from "effect/Effect"
9
27
  import * as Exit from "effect/Exit"
10
28
  import { constTrue, dual } from "effect/Function"
11
29
  import * as Layer from "effect/Layer"
30
+ import * as Option from "effect/Option"
12
31
  import * as Predicate from "effect/Predicate"
13
- import * as ServiceMap from "effect/ServiceMap"
14
32
  import * as Tracer from "effect/Tracer"
15
- import { recordToAttributes, unknownToAttributeValue } from "./internal/attributes.ts"
33
+ import { nanosToHrTime, recordToAttributes, unknownToAttributeValue } from "./internal/attributes.ts"
16
34
  import { Resource } from "./Resource.ts"
17
35
 
18
36
  // =============================================================================
@@ -20,37 +38,45 @@ import { Resource } from "./Resource.ts"
20
38
  // =============================================================================
21
39
 
22
40
  /**
23
- * @since 1.0.0
24
- * @category Services
41
+ * Context service containing the OpenTelemetry `Tracer` used to create spans for Effect tracing.
42
+ *
43
+ * @category services
44
+ * @since 4.0.0
25
45
  */
26
- export class OtelTracer extends ServiceMap.Service<
46
+ export class OtelTracer extends Context.Service<
27
47
  OtelTracer,
28
48
  Otel.Tracer
29
49
  >()("@effect/opentelemetry/Tracer") {}
30
50
 
31
51
  /**
32
- * @since 1.0.0
33
- * @category Services
52
+ * Context service containing the OpenTelemetry `TracerProvider` used to obtain tracers.
53
+ *
54
+ * @category services
55
+ * @since 4.0.0
34
56
  */
35
- export class OtelTracerProvider extends ServiceMap.Service<
57
+ export class OtelTracerProvider extends Context.Service<
36
58
  OtelTracerProvider,
37
59
  Otel.TracerProvider
38
60
  >()("@effect/opentelemetry/Tracer/OtelTracerProvider") {}
39
61
 
40
62
  /**
41
- * @since 1.0.0
42
- * @category Services
63
+ * Context service containing OpenTelemetry trace flags used when constructing external span contexts.
64
+ *
65
+ * @category services
66
+ * @since 4.0.0
43
67
  */
44
- export class OtelTraceFlags extends ServiceMap.Service<
68
+ export class OtelTraceFlags extends Context.Service<
45
69
  OtelTraceFlags,
46
70
  Otel.TraceFlags
47
71
  >()("@effect/opentelemetry/Tracer/OtelTraceFlags") {}
48
72
 
49
73
  /**
50
- * @since 1.0.0
51
- * @category Services
74
+ * Context service containing OpenTelemetry trace state used when constructing external span contexts.
75
+ *
76
+ * @category services
77
+ * @since 4.0.0
52
78
  */
53
- export class OtelTraceState extends ServiceMap.Service<
79
+ export class OtelTraceState extends Context.Service<
54
80
  OtelTraceState,
55
81
  Otel.TraceState
56
82
  >()("@effect/opentelemetry/Tracer/OtelTraceState") {}
@@ -60,8 +86,10 @@ export class OtelTraceState extends ServiceMap.Service<
60
86
  // =============================================================================
61
87
 
62
88
  /**
63
- * @since 1.0.0
64
- * @category Constructors
89
+ * Creates an Effect `Tracer` implementation backed by the configured OpenTelemetry tracer.
90
+ *
91
+ * @category constructors
92
+ * @since 4.0.0
65
93
  */
66
94
  export const make: Effect.Effect<Tracer.Tracer, never, OtelTracer> = Effect.map(
67
95
  Effect.service(OtelTracer),
@@ -91,8 +119,10 @@ export const make: Effect.Effect<Tracer.Tracer, never, OtelTracer> = Effect.map(
91
119
  )
92
120
 
93
121
  /**
94
- * @since 1.0.0
95
- * @category Constructors
122
+ * Creates an Effect external span from an OpenTelemetry span context, preserving trace flags and trace state when provided.
123
+ *
124
+ * @category constructors
125
+ * @since 4.0.0
96
126
  */
97
127
  export const makeExternalSpan = (options: {
98
128
  readonly traceId: string
@@ -100,22 +130,24 @@ export const makeExternalSpan = (options: {
100
130
  readonly traceFlags?: number | undefined
101
131
  readonly traceState?: string | Otel.TraceState | undefined
102
132
  }): Tracer.ExternalSpan => {
103
- let annotations = ServiceMap.empty()
104
-
105
- if (options.traceFlags !== undefined) {
106
- annotations = ServiceMap.add(annotations, OtelTraceFlags, options.traceFlags)
107
- }
133
+ const annotations = Context.mutate(Context.empty(), (annotations) => {
134
+ let next = annotations
135
+ if (options.traceFlags !== undefined) {
136
+ next = Context.add(next, OtelTraceFlags, options.traceFlags)
137
+ }
108
138
 
109
- if (typeof options.traceState === "string") {
110
- try {
111
- const traceState = Otel.createTraceState(options.traceState)
112
- annotations = ServiceMap.add(annotations, OtelTraceState, traceState)
113
- } catch {
114
- //
139
+ if (typeof options.traceState === "string") {
140
+ try {
141
+ next = Context.add(next, OtelTraceState, Otel.createTraceState(options.traceState))
142
+ } catch {
143
+ //
144
+ }
145
+ } else if (options.traceState) {
146
+ next = Context.add(next, OtelTraceState, options.traceState)
115
147
  }
116
- } else if (options.traceState) {
117
- annotations = ServiceMap.add(annotations, OtelTraceState, options.traceState)
118
- }
148
+
149
+ return next
150
+ })
119
151
 
120
152
  return {
121
153
  _tag: "ExternalSpan",
@@ -131,8 +163,10 @@ export const makeExternalSpan = (options: {
131
163
  // =============================================================================
132
164
 
133
165
  /**
134
- * @since 1.0.0
135
- * @category Layers
166
+ * Layer that provides the current global OpenTelemetry tracer provider.
167
+ *
168
+ * @category layers
169
+ * @since 4.0.0
136
170
  */
137
171
  export const layerGlobalProvider: Layer.Layer<OtelTracerProvider> = Layer.sync(
138
172
  OtelTracerProvider,
@@ -140,8 +174,10 @@ export const layerGlobalProvider: Layer.Layer<OtelTracerProvider> = Layer.sync(
140
174
  )
141
175
 
142
176
  /**
143
- * @since 1.0.0
144
- * @category Layers
177
+ * Layer that creates an OpenTelemetry tracer from the provided tracer provider and resource metadata.
178
+ *
179
+ * @category layers
180
+ * @since 4.0.0
145
181
  */
146
182
  export const layerTracer: Layer.Layer<OtelTracer, never, OtelTracerProvider | Resource> = Layer.effect(
147
183
  OtelTracer,
@@ -156,30 +192,47 @@ export const layerTracer: Layer.Layer<OtelTracer, never, OtelTracerProvider | Re
156
192
  )
157
193
 
158
194
  /**
159
- * @since 1.0.0
160
- * @category Layers
195
+ * Layer that creates an OpenTelemetry tracer from the global tracer provider and the current resource.
196
+ *
197
+ * @category layers
198
+ * @since 4.0.0
161
199
  */
162
200
  export const layerGlobalTracer: Layer.Layer<OtelTracer, never, Resource> = layerTracer.pipe(
163
201
  Layer.provide(layerGlobalProvider)
164
202
  )
165
203
 
166
204
  /**
167
- * @since 1.0.0
168
- * @category Layers
205
+ * Layer that installs an Effect tracer backed by the global OpenTelemetry tracer provider.
206
+ *
207
+ * @category layers
208
+ * @since 4.0.0
169
209
  */
170
210
  export const layerGlobal: Layer.Layer<OtelTracer, never, Resource> = Layer.effect(Tracer.Tracer, make).pipe(
171
211
  Layer.provideMerge(layerGlobalTracer)
172
212
  )
173
213
 
174
214
  /**
175
- * @since 1.0.0
176
- * @category Layers
215
+ * Layer that installs the Effect tracer using an `OtelTracer` already provided in the environment.
216
+ *
217
+ * @category layers
218
+ * @since 4.0.0
177
219
  */
178
220
  export const layerWithoutOtelTracer: Layer.Layer<never, never, OtelTracer> = Layer.effect(Tracer.Tracer, make)
179
221
 
180
222
  /**
181
- * @since 1.0.0
182
- * @category Layers
223
+ * Layer that creates an OpenTelemetry tracer from a provider and resource, then installs it as the Effect tracer.
224
+ *
225
+ * **When to use**
226
+ *
227
+ * Use when you already provide an `OtelTracerProvider` and a `Resource`, and
228
+ * want Effect spans backed by a tracer derived from them.
229
+ *
230
+ * @see {@link layerTracer} for creating only the OpenTelemetry tracer service
231
+ * @see {@link layerGlobal} for installing the Effect tracer from the global provider
232
+ * @see {@link layerWithoutOtelTracer} for installing an already-provided `OtelTracer`
233
+ *
234
+ * @category layers
235
+ * @since 4.0.0
183
236
  */
184
237
  export const layer: Layer.Layer<OtelTracer, never, OtelTracerProvider | Resource> = layerWithoutOtelTracer.pipe(
185
238
  Layer.provideMerge(layerTracer)
@@ -193,16 +246,17 @@ const bigint1e6 = BigInt(1_000_000)
193
246
  const bigint1e9 = BigInt(1_000_000_000)
194
247
 
195
248
  /**
196
- * Get the current OpenTelemetry span.
249
+ * Gets the current OpenTelemetry span.
197
250
  *
198
- * Works with both the official OpenTelemetry API (via `Tracer.layer`,
199
- * `NodeSdk.layer`, etc.) and the lightweight OTLP module (`OtlpTracer.layer`).
251
+ * **Details**
200
252
  *
201
- * When using OTLP, the returned span is a wrapper that conforms to the
202
- * OpenTelemetry `Span` interface.
253
+ * This accessor works with both the official OpenTelemetry API, such as
254
+ * `Tracer.layer` and `NodeSdk.layer`, and the lightweight OTLP module, such as
255
+ * `OtlpTracer.layer`. When using OTLP, the returned span is a wrapper that
256
+ * conforms to the OpenTelemetry `Span` interface.
203
257
  *
204
- * @since 1.0.0
205
258
  * @category accessors
259
+ * @since 4.0.0
206
260
  */
207
261
  export const currentOtelSpan: Effect.Effect<Otel.Span, Cause.NoSuchElementError> = Effect.clockWith((clock) =>
208
262
  Effect.map(Effect.currentSpan, (span) =>
@@ -275,7 +329,9 @@ const makeOtelSpan = (span: Tracer.Span, clock: Clock.Clock): Otel.Span => {
275
329
  recordException(exception, timeInput) {
276
330
  const time = convertOtelTimeInput(timeInput, clock)
277
331
  const cause = Cause.fail(exception)
278
- const error = Cause.prettyErrors(cause)[0]
332
+ const error = Cause.prettyErrors(cause, {
333
+ includeCauseInStack: true
334
+ })[0]
279
335
  span.event(error.message, time, {
280
336
  "exception.type": error.name,
281
337
  "exception.message": error.message,
@@ -299,35 +355,41 @@ const convertOtelTimeInput = (input: Otel.TimeInput | undefined, clock: Clock.Cl
299
355
  }
300
356
 
301
357
  /**
302
- * Set the effect's parent span from the given opentelemetry `SpanContext`.
358
+ * Sets an effect's parent span from the given OpenTelemetry `SpanContext`.
303
359
  *
304
- * This is handy when you set up OpenTelemetry outside of Effect and want to
305
- * attach to a parent span.
360
+ * **When to use**
306
361
  *
307
- * @since 1.0.0
308
- * @category Propagation
362
+ * Use when you need an effect to continue a trace from a parent span context
363
+ * produced by OpenTelemetry instrumentation outside Effect.
364
+ *
365
+ * @category propagation
366
+ * @since 4.0.0
309
367
  */
310
368
  export const withSpanContext: {
311
369
  /**
312
- * Set the effect's parent span from the given opentelemetry `SpanContext`.
370
+ * Sets an effect's parent span from the given OpenTelemetry `SpanContext`.
371
+ *
372
+ * **When to use**
313
373
  *
314
- * This is handy when you set up OpenTelemetry outside of Effect and want to
315
- * attach to a parent span.
374
+ * Use when you need an effect to continue a trace from a parent span context
375
+ * produced by OpenTelemetry instrumentation outside Effect.
316
376
  *
317
- * @since 1.0.0
318
- * @category Propagation
377
+ * @category propagation
378
+ * @since 4.0.0
319
379
  */
320
380
  (spanContext: Otel.SpanContext): <A, E, R>(
321
381
  self: Effect.Effect<A, E, R>
322
382
  ) => Effect.Effect<A, E, Exclude<R, Tracer.ParentSpan>>
323
383
  /**
324
- * Set the effect's parent span from the given opentelemetry `SpanContext`.
384
+ * Sets an effect's parent span from the given OpenTelemetry `SpanContext`.
325
385
  *
326
- * This is handy when you set up OpenTelemetry outside of Effect and want to
327
- * attach to a parent span.
386
+ * **When to use**
328
387
  *
329
- * @since 1.0.0
330
- * @category Propagation
388
+ * Use when you need an effect to continue a trace from a parent span context
389
+ * produced by OpenTelemetry instrumentation outside Effect.
390
+ *
391
+ * @category propagation
392
+ * @since 4.0.0
331
393
  */
332
394
  <A, E, R>(self: Effect.Effect<A, E, R>, spanContext: Otel.SpanContext): Effect.Effect<A, E, Exclude<R, Tracer.ParentSpan>>
333
395
  } = dual(2, <A, E, R>(
@@ -356,14 +418,14 @@ export class OtelSpan implements Tracer.Span {
356
418
 
357
419
  readonly name: string
358
420
  readonly kind: Tracer.SpanKind
359
- readonly annotations: ServiceMap.ServiceMap<never>
421
+ readonly annotations: Context.Context<never>
360
422
  readonly links: Array<Tracer.SpanLink>
361
423
  readonly span: Otel.Span
362
424
  readonly spanId: string
363
425
  readonly traceId: string
364
426
  readonly attributes = new Map<string, unknown>()
365
427
  readonly sampled: boolean
366
- readonly parent: Tracer.AnySpan | undefined
428
+ readonly parent: Option.Option<Tracer.AnySpan>
367
429
  status: Tracer.SpanStatus
368
430
 
369
431
  constructor(
@@ -378,9 +440,9 @@ export class OtelSpan implements Tracer.Span {
378
440
  this.links = options.links
379
441
  this.kind = options.kind
380
442
  const active = contextApi.active()
381
- this.parent = options.parent ?? (options?.root !== true) ?
382
- getOtelParent(traceApi, active, options.annotations) :
383
- undefined
443
+ this.parent = options.root !== true
444
+ ? Option.orElse(options.parent, () => getOtelParent(traceApi, active, options.annotations))
445
+ : options.parent
384
446
  this.span = tracer.startSpan(
385
447
  options.name,
386
448
  {
@@ -393,7 +455,9 @@ export class OtelSpan implements Tracer.Span {
393
455
  : undefined as any,
394
456
  kind: kindMap[this.kind]
395
457
  },
396
- this.parent ? populateContext(active, this.parent, options.annotations) : Otel.trace.deleteSpan(active)
458
+ Option.isSome(this.parent) ?
459
+ populateContext(active, this.parent.value, options.annotations) :
460
+ Otel.trace.deleteSpan(active)
397
461
  )
398
462
  const spanContext = this.span.spanContext()
399
463
  this.spanId = spanContext.spanId
@@ -439,7 +503,9 @@ export class OtelSpan implements Tracer.Span {
439
503
  this.span.setAttribute("span.label", "⚠︎ Interrupted")
440
504
  this.span.setAttribute("status.interrupted", true)
441
505
  } else {
442
- const errors = Cause.prettyErrors(exit.cause)
506
+ const errors = Cause.prettyErrors(exit.cause, {
507
+ includeCauseInStack: true
508
+ })
443
509
  if (errors.length > 0) {
444
510
  for (const error of errors) {
445
511
  this.span.recordException(error, hrTime)
@@ -469,30 +535,24 @@ export class OtelSpan implements Tracer.Span {
469
535
  const isSampled = (traceFlags: Otel.TraceFlags): boolean =>
470
536
  (traceFlags & Otel.TraceFlags.SAMPLED) === Otel.TraceFlags.SAMPLED
471
537
 
472
- const nanosToHrTime = (timestamp: bigint): Otel.HrTime => {
473
- return [Number(timestamp / bigint1e9), Number(timestamp % bigint1e9)]
474
- }
475
-
476
538
  const getOtelParent = (
477
539
  tracer: Otel.TraceAPI,
478
540
  context: Otel.Context,
479
- annotations: ServiceMap.ServiceMap<never>
480
- ): Tracer.AnySpan | undefined => {
481
- const active = tracer.getSpan(context)
482
- const otelParent = active ? active.spanContext() : undefined
483
- return otelParent
484
- ? Tracer.externalSpan({
485
- spanId: otelParent.spanId,
486
- traceId: otelParent.traceId,
487
- sampled: (otelParent.traceFlags & 1) === 1,
488
- annotations
489
- })
490
- : undefined
541
+ annotations: Context.Context<never>
542
+ ): Option.Option<Tracer.AnySpan> => {
543
+ const otelParent = tracer.getSpan(context)?.spanContext()
544
+ if (!otelParent) return Option.none()
545
+ return Option.some(Tracer.externalSpan({
546
+ spanId: otelParent.spanId,
547
+ traceId: otelParent.traceId,
548
+ sampled: (otelParent.traceFlags & 1) === 1,
549
+ annotations
550
+ }))
491
551
  }
492
552
 
493
553
  const makeSpanContext = (
494
554
  span: Tracer.AnySpan,
495
- annotations?: ServiceMap.ServiceMap<never>
555
+ annotations?: Context.Context<never>
496
556
  ): Otel.SpanContext => {
497
557
  const traceFlags = makeTraceFlags(span, annotations)
498
558
  const traceState = makeTraceState(span, annotations)!
@@ -507,27 +567,27 @@ const makeSpanContext = (
507
567
 
508
568
  const makeTraceFlags = (
509
569
  span: Tracer.AnySpan,
510
- annotations: ServiceMap.ServiceMap<never> | undefined
570
+ annotations: Context.Context<never> | undefined
511
571
  ): Otel.TraceFlags => {
512
572
  let traceFlags: Otel.TraceFlags | undefined
513
573
  if (Predicate.isNotUndefined(annotations)) {
514
574
  traceFlags = extractTraceService(span, annotations, OtelTraceFlags)
515
575
  if (Predicate.isUndefined(traceFlags)) {
516
- traceFlags = ServiceMap.getOrUndefined(span.annotations, OtelTraceFlags)
576
+ traceFlags = Context.getOrUndefined(span.annotations, OtelTraceFlags)
517
577
  }
518
578
  }
519
- return traceFlags ?? Otel.TraceFlags.SAMPLED
579
+ return traceFlags ?? (span.sampled ? Otel.TraceFlags.SAMPLED : Otel.TraceFlags.NONE)
520
580
  }
521
581
 
522
582
  const makeTraceState = (
523
583
  span: Tracer.AnySpan,
524
- annotations: ServiceMap.ServiceMap<never> | undefined
584
+ annotations: Context.Context<never> | undefined
525
585
  ): Otel.TraceState | undefined => {
526
586
  let traceState: Otel.TraceState | undefined
527
587
  if (Predicate.isNotUndefined(annotations)) {
528
588
  traceState = extractTraceService(span, annotations, OtelTraceState)
529
589
  if (Predicate.isUndefined(traceState)) {
530
- traceState = ServiceMap.getOrUndefined(span.annotations, OtelTraceState)
590
+ traceState = Context.getOrUndefined(span.annotations, OtelTraceState)
531
591
  }
532
592
  }
533
593
  return traceState
@@ -535,20 +595,20 @@ const makeTraceState = (
535
595
 
536
596
  const extractTraceService = <I, S>(
537
597
  parent: Tracer.AnySpan,
538
- annotations: ServiceMap.ServiceMap<never>,
539
- service: ServiceMap.Service<I, S>
598
+ annotations: Context.Context<never>,
599
+ service: Context.Service<I, S>
540
600
  ) => {
541
- const instance = ServiceMap.getOrUndefined(annotations, service)
601
+ const instance = Context.getOrUndefined(annotations, service)
542
602
  if (Predicate.isNotUndefined(instance)) {
543
603
  return instance
544
604
  }
545
- return ServiceMap.getOrUndefined(parent.annotations, service)
605
+ return Context.getOrUndefined(parent.annotations, service)
546
606
  }
547
607
 
548
608
  const populateContext = (
549
609
  context: Otel.Context,
550
610
  span: Tracer.AnySpan,
551
- annotations?: ServiceMap.ServiceMap<never> | undefined
611
+ annotations?: Context.Context<never> | undefined
552
612
  ): Otel.Context =>
553
613
  span instanceof OtelSpan ?
554
614
  Otel.trace.setSpan(context, span.span) :
package/src/Resource.ts CHANGED
@@ -1,27 +1,45 @@
1
1
  /**
2
- * @since 1.0.0
2
+ * OpenTelemetry resource service and layers.
3
+ *
4
+ * An OpenTelemetry resource identifies the process or service that emits spans,
5
+ * metrics, and logs. This module stores that resource in Effect context and
6
+ * provides layers for creating it from explicit service metadata, from
7
+ * `OTEL_SERVICE_NAME` and `OTEL_RESOURCE_ATTRIBUTES`, or as an empty resource.
8
+ * It also includes `configToAttributes` for turning service metadata into raw
9
+ * OpenTelemetry attributes.
10
+ *
11
+ * @since 4.0.0
3
12
  */
4
13
  import type * as OtelApi from "@opentelemetry/api"
5
14
  import * as Resources from "@opentelemetry/resources"
6
15
  import * as OtelSemConv from "@opentelemetry/semantic-conventions"
7
16
  import * as Arr from "effect/Array"
8
17
  import * as Config from "effect/Config"
18
+ import * as Context from "effect/Context"
9
19
  import * as Effect from "effect/Effect"
10
20
  import * as Layer from "effect/Layer"
11
- import * as ServiceMap from "effect/ServiceMap"
12
21
 
13
22
  /**
14
- * @since 1.0.0
15
- * @category Services
23
+ * Service tag for OpenTelemetry metadata attached to emitted telemetry.
24
+ *
25
+ * **When to use**
26
+ *
27
+ * Use to provide process, service, and deployment metadata that should be
28
+ * attached to spans, metrics, and logs.
29
+ *
30
+ * @category services
31
+ * @since 4.0.0
16
32
  */
17
- export class Resource extends ServiceMap.Service<
33
+ export class Resource extends Context.Service<
18
34
  Resource,
19
35
  Resources.Resource
20
36
  >()("@effect/opentelemetry/Resource") {}
21
37
 
22
38
  /**
23
- * @since 1.0.0
24
- * @category Layers
39
+ * Creates a `Resource` layer from service metadata and additional OpenTelemetry attributes.
40
+ *
41
+ * @category layers
42
+ * @since 4.0.0
25
43
  */
26
44
  export const layer = (config: {
27
45
  readonly serviceName: string
@@ -34,8 +52,30 @@ export const layer = (config: {
34
52
  )
35
53
 
36
54
  /**
37
- * @since 1.0.0
38
- * @category Configuration
55
+ * Converts resource configuration into OpenTelemetry attributes, adding service name, optional service version, and telemetry SDK metadata.
56
+ *
57
+ * **When to use**
58
+ *
59
+ * Use to turn explicit service metadata into a raw OpenTelemetry attribute map
60
+ * for lower-level resource construction or merging with environment-derived
61
+ * attributes via `layerFromEnv`.
62
+ *
63
+ * **Details**
64
+ *
65
+ * The returned record copies `attributes` first, then sets `service.name`,
66
+ * `telemetry.sdk.name`, and `telemetry.sdk.language`. `service.version` is
67
+ * included only when `serviceVersion` is provided.
68
+ *
69
+ * **Gotchas**
70
+ *
71
+ * Custom values for `service.name` and `telemetry.sdk.*` are overwritten by this
72
+ * helper. An empty `serviceVersion` is treated as absent.
73
+ *
74
+ * @see {@link layer} for creating a `Resource` layer from explicit metadata
75
+ * @see {@link layerFromEnv} for merging attributes with OpenTelemetry environment variables
76
+ *
77
+ * @category configuration
78
+ * @since 4.0.0
39
79
  */
40
80
  export const configToAttributes = (options: {
41
81
  readonly serviceName: string
@@ -57,8 +97,10 @@ export const configToAttributes = (options: {
57
97
  }
58
98
 
59
99
  /**
60
- * @since 1.0.0
61
- * @category Layers
100
+ * Creates a `Resource` layer from OpenTelemetry environment variables, optionally merging additional attributes.
101
+ *
102
+ * @category layers
103
+ * @since 4.0.0
62
104
  */
63
105
  export const layerFromEnv = (
64
106
  additionalAttributes?:
@@ -70,7 +112,7 @@ export const layerFromEnv = (
70
112
  Effect.gen(function*() {
71
113
  const serviceName = yield* Config.option(Config.string("OTEL_SERVICE_NAME"))
72
114
  const attributes = yield* Config.string("OTEL_RESOURCE_ATTRIBUTES").pipe(
73
- Config.withDefault(() => ""),
115
+ Config.withDefault(""),
74
116
  Config.map((s) => {
75
117
  const attrs = s.split(",")
76
118
  return Arr.reduce(attrs, {} as OtelApi.Attributes, (acc, attr) => {
@@ -94,8 +136,10 @@ export const layerFromEnv = (
94
136
  )
95
137
 
96
138
  /**
97
- * @since 1.0.0
98
- * @category Layers
139
+ * Layer that provides an empty OpenTelemetry resource.
140
+ *
141
+ * @category layers
142
+ * @since 4.0.0
99
143
  */
100
144
  export const layerEmpty = Layer.succeed(
101
145
  Resource,