@effect/opentelemetry 4.0.0-beta.7 → 4.0.0-beta.71

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/src/Logger.ts CHANGED
@@ -1,33 +1,104 @@
1
1
  /**
2
- * @since 1.0.0
2
+ * Connects Effect logging to the OpenTelemetry Logs SDK.
3
+ *
4
+ * This module turns Effect log events into OpenTelemetry log records. It
5
+ * provides the `OtelLoggerProvider` service, a `Logger` implementation created
6
+ * by {@link make}, a {@link layer} that installs it into Effect logging, and
7
+ * {@link layerLoggerProvider} for creating a scoped SDK `LoggerProvider` from
8
+ * one or more `LogRecordProcessor`s.
9
+ *
10
+ * **Mental model**
11
+ *
12
+ * Effect decides when a log is emitted and supplies the message, fiber id, log
13
+ * level, annotations, log spans, and active parent span. This module maps that
14
+ * data into an OpenTelemetry log record, including severity text/number, trace
15
+ * and span identifiers when available, and timestamps from the Effect `Clock`.
16
+ *
17
+ * **Common tasks**
18
+ *
19
+ * Use {@link layerLoggerProvider} when the application wants this package to own
20
+ * the OpenTelemetry logger provider lifecycle. Provide it with processors such
21
+ * as OTLP, console, or vendor-specific exporters, then install {@link layer} so
22
+ * regular Effect logging emits records through that provider. If the provider is
23
+ * created elsewhere, supply `OtelLoggerProvider` yourself and still use
24
+ * {@link layer} or {@link make}.
25
+ *
26
+ * **Gotchas**
27
+ *
28
+ * This module does not choose an exporter. Export behavior, batching, retries,
29
+ * and delivery guarantees come from the configured OpenTelemetry processors.
30
+ * The scoped provider is force-flushed and shut down when the layer is released,
31
+ * using the configured shutdown timeout; externally managed providers should be
32
+ * flushed and shut down by the owner to avoid dropping buffered logs.
33
+ *
34
+ * @since 4.0.0
3
35
  */
36
+ import { SeverityNumber } from "@opentelemetry/api-logs"
4
37
  import * as Otel from "@opentelemetry/sdk-logs"
5
38
  import type { NonEmptyReadonlyArray } from "effect/Array"
6
39
  import * as Arr from "effect/Array"
7
40
  import * as Clock from "effect/Clock"
41
+ import * as Context from "effect/Context"
8
42
  import type * as Duration from "effect/Duration"
9
43
  import * as Effect from "effect/Effect"
10
44
  import * as Layer from "effect/Layer"
11
45
  import * as Logger from "effect/Logger"
12
- import * as LogLevel from "effect/LogLevel"
46
+ import type * as LogLevel from "effect/LogLevel"
13
47
  import * as Predicate from "effect/Predicate"
14
- import * as ServiceMap from "effect/ServiceMap"
48
+ import * as References from "effect/References"
15
49
  import * as Tracer from "effect/Tracer"
16
- import { unknownToAttributeValue } from "./internal/attributes.ts"
50
+ import { nanosToHrTime, unknownToAttributeValue } from "./internal/attributes.ts"
17
51
  import { Resource } from "./Resource.ts"
18
52
 
19
53
  /**
20
- * @since 1.0.0
21
- * @category Services
54
+ * Context service containing the OpenTelemetry `LoggerProvider` used to emit Effect log records.
55
+ *
56
+ * @category services
57
+ * @since 4.0.0
22
58
  */
23
- export class OtelLoggerProvider extends ServiceMap.Service<
59
+ export class OtelLoggerProvider extends Context.Service<
24
60
  OtelLoggerProvider,
25
61
  Otel.LoggerProvider
26
62
  >()("@effect/opentelemetry/Logger/OtelLoggerProvider") {}
27
63
 
28
64
  /**
29
- * @since 1.0.0
30
- * @category Constructors
65
+ * Maps an Effect `LogLevel` to the corresponding OpenTelemetry `SeverityNumber`.
66
+ *
67
+ * **Details**
68
+ *
69
+ * OpenTelemetry log severity numbers are in the range `1` through `24`. This
70
+ * function maps from Effect's log levels instead of using
71
+ * `LogLevel.getOrdinal`, whose internal sort ordinals, such as the `Info`
72
+ * ordinal `20000`, fall outside the OpenTelemetry logs data model and can be
73
+ * treated as `UNSPECIFIED` by validating backends.
74
+ *
75
+ * @category converting
76
+ * @since 4.0.0
77
+ */
78
+ export const logLevelToSeverityNumber = (level: LogLevel.LogLevel): SeverityNumber => {
79
+ switch (level) {
80
+ case "Trace":
81
+ return SeverityNumber.TRACE
82
+ case "Debug":
83
+ return SeverityNumber.DEBUG
84
+ case "Info":
85
+ return SeverityNumber.INFO
86
+ case "Warn":
87
+ return SeverityNumber.WARN
88
+ case "Error":
89
+ return SeverityNumber.ERROR
90
+ case "Fatal":
91
+ return SeverityNumber.FATAL
92
+ default:
93
+ return SeverityNumber.UNSPECIFIED
94
+ }
95
+ }
96
+
97
+ /**
98
+ * Creates an Effect logger that emits log records through the configured OpenTelemetry logger provider.
99
+ *
100
+ * @category constructors
101
+ * @since 4.0.0
31
102
  */
32
103
  export const make: Effect.Effect<
33
104
  Logger.Logger<unknown, void>,
@@ -43,40 +114,60 @@ export const make: Effect.Effect<
43
114
  fiberId: options.fiber.id
44
115
  }
45
116
 
46
- const span = ServiceMap.getOrUndefined(options.fiber.services, Tracer.ParentSpan)
117
+ const span = Context.getOrUndefined(options.fiber.context, Tracer.ParentSpan)
47
118
 
48
119
  if (Predicate.isNotUndefined(span)) {
49
120
  attributes.spanId = span.spanId
50
121
  attributes.traceId = span.traceId
51
122
  }
52
123
 
53
- // TODO: add back after log spans / annotations
54
- // for (const [key, value] of options.annotations) {
55
- // attributes[key] = unknownToAttributeValue(value)
56
- // }
57
- // const now = options.date.getTime()
58
- // for (const span of options.spans) {
59
- // attributes[`logSpan.${span.label}`] = `${now - span.startTime}ms`
60
- // }
124
+ for (const [key, value] of Object.entries(options.fiber.getRef(References.CurrentLogAnnotations))) {
125
+ attributes[key] = unknownToAttributeValue(value)
126
+ }
127
+ const now = options.date.getTime()
128
+ for (const [label, startTime] of options.fiber.getRef(References.CurrentLogSpans)) {
129
+ attributes[`logSpan.${label}`] = `${now - startTime}ms`
130
+ }
61
131
 
62
132
  const message = Arr.ensure(options.message).map(unknownToAttributeValue)
133
+ const hrTime = nanosToHrTime(clock.currentTimeNanosUnsafe())
63
134
  otelLogger.emit({
64
135
  body: message.length === 1 ? message[0] : message,
65
136
  severityText: options.logLevel,
66
- severityNumber: LogLevel.getOrdinal(options.logLevel),
67
- timestamp: options.date,
68
- observedTimestamp: clock.currentTimeMillisUnsafe(),
137
+ severityNumber: logLevelToSeverityNumber(options.logLevel),
138
+ timestamp: hrTime,
139
+ observedTimestamp: hrTime,
69
140
  attributes
70
141
  })
71
142
  })
72
143
  })
73
144
 
74
145
  /**
75
- * @since 1.0.0
76
- * @category Layers
146
+ * Creates a layer that installs the OpenTelemetry-backed Effect logger, merging with existing loggers by default.
147
+ *
148
+ * **When to use**
149
+ *
150
+ * Use to install the OpenTelemetry-backed Effect logger in an application that
151
+ * has an `OtelLoggerProvider`, so standard Effect logging emits OpenTelemetry
152
+ * log records.
153
+ *
154
+ * **Details**
155
+ *
156
+ * The layer installs the logger created by `make`. `mergeWithExisting` defaults
157
+ * to `true`; set it to `false` to replace the current logger set.
158
+ *
159
+ * @see {@link make} for constructing the logger directly
160
+ * @see {@link layerLoggerProvider} for creating the required logger provider
161
+ *
162
+ * @category layers
163
+ * @since 4.0.0
77
164
  */
78
165
  export const layer = (options: {
79
166
  /**
167
+ * Whether to merge the OpenTelemetry logger with existing loggers.
168
+ *
169
+ * **Details**
170
+ *
80
171
  * If set to `true`, the OpenTelemetry logger will be merged with existing
81
172
  * loggers in the application.
82
173
  *
@@ -92,8 +183,10 @@ export const layer = (options: {
92
183
  })
93
184
 
94
185
  /**
95
- * @since 1.0.0
96
- * @category Layers
186
+ * Creates a scoped OpenTelemetry logger provider from one or more log record processors, using the current `Resource` and flushing and shutting down the provider when the layer is released.
187
+ *
188
+ * @category layers
189
+ * @since 4.0.0
97
190
  */
98
191
  export const layerLoggerProvider = (
99
192
  processor: Otel.LogRecordProcessor | NonEmptyReadonlyArray<Otel.LogRecordProcessor>,
package/src/Metrics.ts CHANGED
@@ -1,5 +1,37 @@
1
1
  /**
2
- * @since 1.0.0
2
+ * OpenTelemetry metric export bridge for Effect metrics.
3
+ *
4
+ * Effect applications record metrics through Effect's metric APIs. This module
5
+ * exposes the current Effect metric snapshot as an OpenTelemetry
6
+ * `MetricProducer` and registers it with SDK `MetricReader`s so existing
7
+ * OpenTelemetry exporters can deliver those metrics to OTLP, Prometheus, or
8
+ * vendor backends.
9
+ *
10
+ * **Mental model**
11
+ *
12
+ * {@link makeProducer} captures the current Effect context and `Resource` and
13
+ * builds a producer that OpenTelemetry readers can pull from.
14
+ * {@link registerProducer} attaches that producer to one or more readers for
15
+ * the lifetime of a scope. {@link layer} composes both steps and is the path
16
+ * used by the Node and Web SDK layers when metric readers are configured.
17
+ *
18
+ * **Common tasks**
19
+ *
20
+ * - Install Effect metrics into OpenTelemetry with {@link layer}
21
+ * - Build a producer manually with {@link makeProducer}
22
+ * - Attach an existing producer to readers with {@link registerProducer}
23
+ * - Choose cumulative or delta export with {@link TemporalityPreference}
24
+ *
25
+ * **Gotchas**
26
+ *
27
+ * Readers are shut down when the layer scope closes, so periodic exporters need
28
+ * the application runtime to stay alive long enough for collection and export.
29
+ * This module defaults to cumulative temporality; configure
30
+ * `temporality: "delta"` only when the backend expects interval values. Export
31
+ * protocol, batching, and delivery behavior come from the OpenTelemetry
32
+ * reader/exporter, not from this bridge.
33
+ *
34
+ * @since 4.0.0
3
35
  */
4
36
  import type { MetricProducer, MetricReader } from "@opentelemetry/sdk-metrics"
5
37
  import type * as Arr from "effect/Array"
@@ -15,35 +47,50 @@ import { Resource } from "./Resource.ts"
15
47
  * Determines how metric values relate to the time interval over which they
16
48
  * are aggregated.
17
49
  *
18
- * - `cumulative`: Reports total since a fixed start time. Each data point
19
- * depends on all previous measurements. This is the default behavior.
50
+ * **Details**
20
51
  *
21
- * - `delta`: Reports changes since the last export. Each interval is
22
- * independent with no dependency on previous measurements.
52
+ * `cumulative` reports total since a fixed start time. Each data point depends
53
+ * on all previous measurements. This is the default behavior. `delta` reports
54
+ * changes since the last export. Each interval is independent with no
55
+ * dependency on previous measurements.
23
56
  *
24
- * @since 1.0.0
25
- * @category Models
57
+ * @category models
58
+ * @since 4.0.0
26
59
  */
27
60
  export type TemporalityPreference = "cumulative" | "delta"
28
61
 
29
62
  /**
30
63
  * Creates an OpenTelemetry metric producer from Effect metrics.
31
64
  *
32
- * @since 1.0.0
33
- * @category Constructors
65
+ * **When to use**
66
+ *
67
+ * Use to create a `MetricProducer` when you need to wire Effect metrics into
68
+ * OpenTelemetry manually instead of using the scoped `layer` helper.
69
+ *
70
+ * **Details**
71
+ *
72
+ * Requires the current OpenTelemetry `Resource`, captures the current Effect
73
+ * context, and uses cumulative temporality by default. Pass `"delta"` for
74
+ * interval-based values.
75
+ *
76
+ * @see {@link registerProducer} for attaching a producer to metric readers
77
+ * @see {@link layer} for creating and registering a producer in a scoped layer
78
+ *
79
+ * @category constructors
80
+ * @since 4.0.0
34
81
  */
35
82
  export const makeProducer = (temporality?: TemporalityPreference): Effect.Effect<MetricProducer, never, Resource> =>
36
83
  Effect.gen(function*() {
37
84
  const resource = yield* Resource
38
- const services = yield* Effect.services<never>()
85
+ const services = yield* Effect.context<never>()
39
86
  return new MetricProducerImpl(resource, services, temporality)
40
87
  })
41
88
 
42
89
  /**
43
90
  * Registers a metric producer with one or more metric readers.
44
91
  *
45
- * @since 1.0.0
46
- * @category Constructors
92
+ * @category constructors
93
+ * @since 4.0.0
47
94
  */
48
95
  export const registerProducer = (
49
96
  self: MetricProducer,
@@ -74,7 +121,8 @@ export const registerProducer = (
74
121
  /**
75
122
  * Creates a Layer that registers a metric producer with metric readers.
76
123
  *
77
- * @example
124
+ * **Example** (Creating a metrics layer with temporality)
125
+ *
78
126
  * ```ts
79
127
  * import { Metrics } from "@effect/opentelemetry"
80
128
  * import { PeriodicExportingMetricReader } from "@opentelemetry/sdk-metrics"
@@ -98,8 +146,8 @@ export const registerProducer = (
98
146
  * )
99
147
  * ```
100
148
  *
101
- * @since 1.0.0
102
- * @category Layers
149
+ * @category layers
150
+ * @since 4.0.0
103
151
  */
104
152
  export const layer = (
105
153
  evaluate: LazyArg<MetricReader | Arr.NonEmptyReadonlyArray<MetricReader>>,
package/src/NodeSdk.ts CHANGED
@@ -1,5 +1,27 @@
1
1
  /**
2
- * @since 1.0.0
2
+ * Provides an Effect layer for configuring OpenTelemetry in Node.js
3
+ * processes. The module wires the Effect tracer, metrics producer, and logger
4
+ * into OpenTelemetry SDK providers when span processors, metric readers, or log
5
+ * record processors are supplied, and it builds the shared resource from
6
+ * `OTEL_SERVICE_NAME`, `OTEL_RESOURCE_ATTRIBUTES`, and optional explicit
7
+ * service metadata.
8
+ *
9
+ * Use this module in Node services, workers, CLIs, or server runtimes that need
10
+ * Effect spans, metrics, and logs exported through OpenTelemetry processors and
11
+ * exporters. Telemetry is enabled only for the configured signal types, so an
12
+ * application can install tracing alone, metrics alone, logging alone, or any
13
+ * combination of them from the same layer.
14
+ *
15
+ * The layer is scoped. Tracer and logger providers are force-flushed and shut
16
+ * down when the scope is released, metric readers are shut down with the same
17
+ * lifecycle, and all shutdown waits are bounded by `shutdownTimeout` with a
18
+ * default of three seconds. Keep the layer scope alive for the lifetime of the
19
+ * process and release it during graceful shutdown so batched exporters have a
20
+ * chance to export final telemetry. When combining this layer with Node
21
+ * auto-instrumentations, register instrumentation before importing modules that
22
+ * should be patched, because many Node instrumentations hook module loading.
23
+ *
24
+ * @since 4.0.0
3
25
  */
4
26
  import type * as Otel from "@opentelemetry/api"
5
27
  import type { LoggerProviderConfig, LogRecordProcessor } from "@opentelemetry/sdk-logs"
@@ -18,8 +40,10 @@ import * as Resource from "./Resource.ts"
18
40
  import * as Tracer from "./Tracer.ts"
19
41
 
20
42
  /**
21
- * @since 1.0.0
22
- * @category Models
43
+ * Configuration for the Node OpenTelemetry layer, including optional tracing, metrics, logging, resource, and shutdown settings.
44
+ *
45
+ * @category models
46
+ * @since 4.0.0
23
47
  */
24
48
  export interface Configuration {
25
49
  readonly spanProcessor?: SpanProcessor | ReadonlyArray<SpanProcessor> | undefined
@@ -38,8 +62,10 @@ export interface Configuration {
38
62
  }
39
63
 
40
64
  /**
41
- * @since 1.0.0
42
- * @category Layers
65
+ * Creates a scoped Node OpenTelemetry tracer provider from one or more span processors and shuts it down when the layer is released.
66
+ *
67
+ * @category layers
68
+ * @since 4.0.0
43
69
  */
44
70
  export const layerTracerProvider = (
45
71
  processor: SpanProcessor | NonEmptyReadonlyArray<SpanProcessor>,
@@ -71,18 +97,75 @@ export const layerTracerProvider = (
71
97
  )
72
98
 
73
99
  /**
74
- * @since 1.0.0
75
- * @category Layers
100
+ * Creates a Node OpenTelemetry layer from configuration, enabling tracing, metrics, and logging only when their processors or readers are supplied.
101
+ *
102
+ * **When to use**
103
+ *
104
+ * Use to install OpenTelemetry support for a Node.js Effect application from
105
+ * one configuration object, enabling tracing, metrics, logging, or any
106
+ * combination of those signals based on the processors and readers supplied.
107
+ *
108
+ * **Details**
109
+ *
110
+ * The configuration can be provided lazily or effectfully. The layer always
111
+ * provides `Resource.Resource`, building it from environment variables and any
112
+ * explicit resource metadata in the configuration.
113
+ *
114
+ * **Gotchas**
115
+ *
116
+ * Register Node auto-instrumentations before importing modules that should be
117
+ * patched, because many Node instrumentations hook module loading.
118
+ *
119
+ * @category layers
120
+ * @since 4.0.0
76
121
  */
77
122
  export const layer: {
78
123
  /**
79
- * @since 1.0.0
80
- * @category Layers
124
+ * Creates a Node OpenTelemetry layer from configuration, enabling tracing, metrics, and logging only when their processors or readers are supplied.
125
+ *
126
+ * **When to use**
127
+ *
128
+ * Use to install OpenTelemetry support for a Node.js Effect application from
129
+ * one configuration object, enabling tracing, metrics, logging, or any
130
+ * combination of those signals based on the processors and readers supplied.
131
+ *
132
+ * **Details**
133
+ *
134
+ * The configuration can be provided lazily or effectfully. The layer always
135
+ * provides `Resource.Resource`, building it from environment variables and any
136
+ * explicit resource metadata in the configuration.
137
+ *
138
+ * **Gotchas**
139
+ *
140
+ * Register Node auto-instrumentations before importing modules that should be
141
+ * patched, because many Node instrumentations hook module loading.
142
+ *
143
+ * @category layers
144
+ * @since 4.0.0
81
145
  */
82
146
  (evaluate: LazyArg<Configuration>): Layer.Layer<Resource.Resource>
83
147
  /**
84
- * @since 1.0.0
85
- * @category Layers
148
+ * Creates a Node OpenTelemetry layer from configuration, enabling tracing, metrics, and logging only when their processors or readers are supplied.
149
+ *
150
+ * **When to use**
151
+ *
152
+ * Use to install OpenTelemetry support for a Node.js Effect application from
153
+ * one configuration object, enabling tracing, metrics, logging, or any
154
+ * combination of those signals based on the processors and readers supplied.
155
+ *
156
+ * **Details**
157
+ *
158
+ * The configuration can be provided lazily or effectfully. The layer always
159
+ * provides `Resource.Resource`, building it from environment variables and any
160
+ * explicit resource metadata in the configuration.
161
+ *
162
+ * **Gotchas**
163
+ *
164
+ * Register Node auto-instrumentations before importing modules that should be
165
+ * patched, because many Node instrumentations hook module loading.
166
+ *
167
+ * @category layers
168
+ * @since 4.0.0
86
169
  */
87
170
  <R, E>(evaluate: Effect.Effect<Configuration, E, R>): Layer.Layer<Resource.Resource, E, R>
88
171
  } = (
@@ -130,7 +213,9 @@ export const layer: {
130
213
  )
131
214
 
132
215
  /**
216
+ * Layer that provides an empty OpenTelemetry `Resource`.
217
+ *
218
+ * @category layers
133
219
  * @since 2.0.0
134
- * @category layer
135
220
  */
136
221
  export const layerEmpty: Layer.Layer<Resource.Resource> = Resource.layerEmpty
package/src/Resource.ts CHANGED
@@ -1,27 +1,61 @@
1
1
  /**
2
- * @since 1.0.0
2
+ * OpenTelemetry resource service for Effect telemetry 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 so
6
+ * tracer, metric, logger, Node SDK, and Web SDK layers can create providers with
7
+ * consistent service metadata.
8
+ *
9
+ * **Mental model**
10
+ *
11
+ * Resource attributes describe stable producer metadata such as `service.name`,
12
+ * `service.version`, deployment, process, or environment attributes. They are
13
+ * attached to telemetry providers, not to individual spans or log records.
14
+ *
15
+ * **Common tasks**
16
+ *
17
+ * Use `layer` when service metadata is configured in code, `layerFromEnv` when
18
+ * deployment supplies `OTEL_SERVICE_NAME` or `OTEL_RESOURCE_ATTRIBUTES`, and
19
+ * `layerEmpty` for tests or integrations that intentionally provide no resource
20
+ * attributes. `configToAttributes` converts the explicit configuration shape
21
+ * into OpenTelemetry semantic-convention attributes for composition with other
22
+ * resource sources.
23
+ *
24
+ * **Gotchas**
25
+ *
26
+ * `layer` merges custom attributes first and then writes `service.name` and
27
+ * `telemetry.sdk.*`, so those keys are controlled by this package. In
28
+ * `layerFromEnv`, `OTEL_SERVICE_NAME` overrides `service.name` from
29
+ * `OTEL_RESOURCE_ATTRIBUTES`, and any additional attributes passed to the layer
30
+ * are merged last.
31
+ *
32
+ * @since 4.0.0
3
33
  */
4
34
  import type * as OtelApi from "@opentelemetry/api"
5
35
  import * as Resources from "@opentelemetry/resources"
6
36
  import * as OtelSemConv from "@opentelemetry/semantic-conventions"
7
37
  import * as Arr from "effect/Array"
8
38
  import * as Config from "effect/Config"
39
+ import * as Context from "effect/Context"
9
40
  import * as Effect from "effect/Effect"
10
41
  import * as Layer from "effect/Layer"
11
- import * as ServiceMap from "effect/ServiceMap"
12
42
 
13
43
  /**
14
- * @since 1.0.0
15
- * @category Services
44
+ * Context service containing the OpenTelemetry `Resource` associated with emitted telemetry.
45
+ *
46
+ * @category services
47
+ * @since 4.0.0
16
48
  */
17
- export class Resource extends ServiceMap.Service<
49
+ export class Resource extends Context.Service<
18
50
  Resource,
19
51
  Resources.Resource
20
52
  >()("@effect/opentelemetry/Resource") {}
21
53
 
22
54
  /**
23
- * @since 1.0.0
24
- * @category Layers
55
+ * Creates a `Resource` layer from service metadata and additional OpenTelemetry attributes.
56
+ *
57
+ * @category layers
58
+ * @since 4.0.0
25
59
  */
26
60
  export const layer = (config: {
27
61
  readonly serviceName: string
@@ -34,8 +68,30 @@ export const layer = (config: {
34
68
  )
35
69
 
36
70
  /**
37
- * @since 1.0.0
38
- * @category Configuration
71
+ * Converts resource configuration into OpenTelemetry attributes, adding service name, optional service version, and telemetry SDK metadata.
72
+ *
73
+ * **When to use**
74
+ *
75
+ * Use to turn explicit service metadata into a raw OpenTelemetry attribute map
76
+ * for lower-level resource construction or for merging with environment-derived
77
+ * attributes via `layerFromEnv`.
78
+ *
79
+ * **Details**
80
+ *
81
+ * The returned record copies `attributes` first, then sets `service.name`,
82
+ * `telemetry.sdk.name`, and `telemetry.sdk.language`. `service.version` is
83
+ * included only when `serviceVersion` is provided.
84
+ *
85
+ * **Gotchas**
86
+ *
87
+ * Custom values for `service.name` and `telemetry.sdk.*` are overwritten by this
88
+ * helper. An empty `serviceVersion` is treated as absent.
89
+ *
90
+ * @see {@link layer} for creating a `Resource` layer from explicit metadata
91
+ * @see {@link layerFromEnv} for merging attributes with OpenTelemetry environment variables
92
+ *
93
+ * @category configuration
94
+ * @since 4.0.0
39
95
  */
40
96
  export const configToAttributes = (options: {
41
97
  readonly serviceName: string
@@ -57,8 +113,10 @@ export const configToAttributes = (options: {
57
113
  }
58
114
 
59
115
  /**
60
- * @since 1.0.0
61
- * @category Layers
116
+ * Creates a `Resource` layer from OpenTelemetry environment variables, optionally merging additional attributes.
117
+ *
118
+ * @category layers
119
+ * @since 4.0.0
62
120
  */
63
121
  export const layerFromEnv = (
64
122
  additionalAttributes?:
@@ -70,7 +128,7 @@ export const layerFromEnv = (
70
128
  Effect.gen(function*() {
71
129
  const serviceName = yield* Config.option(Config.string("OTEL_SERVICE_NAME"))
72
130
  const attributes = yield* Config.string("OTEL_RESOURCE_ATTRIBUTES").pipe(
73
- Config.withDefault(() => ""),
131
+ Config.withDefault(""),
74
132
  Config.map((s) => {
75
133
  const attrs = s.split(",")
76
134
  return Arr.reduce(attrs, {} as OtelApi.Attributes, (acc, attr) => {
@@ -94,8 +152,10 @@ export const layerFromEnv = (
94
152
  )
95
153
 
96
154
  /**
97
- * @since 1.0.0
98
- * @category Layers
155
+ * Layer that provides an empty OpenTelemetry resource.
156
+ *
157
+ * @category layers
158
+ * @since 4.0.0
99
159
  */
100
160
  export const layerEmpty = Layer.succeed(
101
161
  Resource,