effect 4.0.0-beta.76 → 4.0.0-beta.77
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/Config.d.ts +25 -1
- package/dist/Config.d.ts.map +1 -1
- package/dist/Config.js +32 -0
- package/dist/Config.js.map +1 -1
- package/dist/unstable/observability/Otlp.d.ts +18 -0
- package/dist/unstable/observability/Otlp.d.ts.map +1 -1
- package/dist/unstable/observability/Otlp.js +20 -0
- package/dist/unstable/observability/Otlp.js.map +1 -1
- package/dist/unstable/observability/OtlpLogger.d.ts +17 -1
- package/dist/unstable/observability/OtlpLogger.d.ts.map +1 -1
- package/dist/unstable/observability/OtlpLogger.js +49 -0
- package/dist/unstable/observability/OtlpLogger.js.map +1 -1
- package/dist/unstable/observability/OtlpMetrics.d.ts +14 -0
- package/dist/unstable/observability/OtlpMetrics.d.ts.map +1 -1
- package/dist/unstable/observability/OtlpMetrics.js +45 -0
- package/dist/unstable/observability/OtlpMetrics.js.map +1 -1
- package/dist/unstable/observability/OtlpResource.d.ts +3 -3
- package/dist/unstable/observability/OtlpResource.d.ts.map +1 -1
- package/dist/unstable/observability/OtlpResource.js +12 -11
- package/dist/unstable/observability/OtlpResource.js.map +1 -1
- package/dist/unstable/observability/OtlpTracer.d.ts +15 -0
- package/dist/unstable/observability/OtlpTracer.d.ts.map +1 -1
- package/dist/unstable/observability/OtlpTracer.js +46 -0
- package/dist/unstable/observability/OtlpTracer.js.map +1 -1
- package/dist/unstable/observability/internal/otlpEnv.d.ts +8 -0
- package/dist/unstable/observability/internal/otlpEnv.d.ts.map +1 -0
- package/dist/unstable/observability/internal/otlpEnv.js +30 -0
- package/dist/unstable/observability/internal/otlpEnv.js.map +1 -0
- package/package.json +1 -1
- package/src/Config.ts +44 -0
- package/src/unstable/observability/Otlp.ts +36 -0
- package/src/unstable/observability/OtlpLogger.ts +56 -1
- package/src/unstable/observability/OtlpMetrics.ts +51 -0
- package/src/unstable/observability/OtlpResource.ts +27 -16
- package/src/unstable/observability/OtlpTracer.ts +52 -0
- package/src/unstable/observability/internal/otlpEnv.ts +58 -0
|
@@ -25,14 +25,17 @@
|
|
|
25
25
|
*/
|
|
26
26
|
import * as Arr from "../../Array.ts"
|
|
27
27
|
import { Clock } from "../../Clock.ts"
|
|
28
|
+
import * as Config from "../../Config.ts"
|
|
28
29
|
import * as Duration from "../../Duration.ts"
|
|
29
30
|
import * as Effect from "../../Effect.ts"
|
|
30
31
|
import * as Layer from "../../Layer.ts"
|
|
31
32
|
import * as Metric from "../../Metric.ts"
|
|
33
|
+
import * as Option from "../../Option.ts"
|
|
32
34
|
import type * as Scope from "../../Scope.ts"
|
|
33
35
|
import type * as Headers from "../http/Headers.ts"
|
|
34
36
|
import type { HttpBody } from "../http/HttpBody.ts"
|
|
35
37
|
import type * as HttpClient from "../http/HttpClient.ts"
|
|
38
|
+
import * as OtlpEnv from "./internal/otlpEnv.ts"
|
|
36
39
|
import * as Exporter from "./OtlpExporter.ts"
|
|
37
40
|
import type { Fixed64, KeyValue } from "./OtlpResource.ts"
|
|
38
41
|
import * as OtlpResource from "./OtlpResource.ts"
|
|
@@ -475,6 +478,54 @@ export const layer = (options: {
|
|
|
475
478
|
readonly temporality?: AggregationTemporality | undefined
|
|
476
479
|
}): Layer.Layer<never, never, HttpClient.HttpClient | OtlpSerialization> => Layer.effectDiscard(make(options))
|
|
477
480
|
|
|
481
|
+
/**
|
|
482
|
+
* Creates an OTLP metrics layer from OpenTelemetry configuration.
|
|
483
|
+
*
|
|
484
|
+
* @category layers
|
|
485
|
+
* @since 4.0.0
|
|
486
|
+
*/
|
|
487
|
+
export const layerFromConfig = (options?: {
|
|
488
|
+
readonly resource?: {
|
|
489
|
+
readonly serviceName?: string | undefined
|
|
490
|
+
readonly serviceVersion?: string | undefined
|
|
491
|
+
readonly attributes?: Record<string, unknown>
|
|
492
|
+
} | undefined
|
|
493
|
+
readonly headers?: Headers.Input | undefined
|
|
494
|
+
}): Layer.Layer<never, never, HttpClient.HttpClient | OtlpSerialization> =>
|
|
495
|
+
Effect.gen(function*() {
|
|
496
|
+
const { disabled, endpoint, exporters } = yield* Config.all({
|
|
497
|
+
disabled: Config.boolean("OTEL_SDK_DISABLED").pipe(Config.withDefault(false)),
|
|
498
|
+
endpoint: OtlpEnv.endpoint("METRICS"),
|
|
499
|
+
exporters: OtlpEnv.exporters("METRICS")
|
|
500
|
+
})
|
|
501
|
+
if (disabled || !endpoint || !exporters.includes("otlp")) {
|
|
502
|
+
return Layer.empty
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
const { baseTimeout, metricsTimeout, exportTimeout, exportInterval, temporalityPreference } = yield* Config.all({
|
|
506
|
+
baseTimeout: Config.option(Config.int("OTEL_EXPORTER_OTLP_TIMEOUT")),
|
|
507
|
+
metricsTimeout: Config.option(Config.int("OTEL_EXPORTER_OTLP_METRICS_TIMEOUT")),
|
|
508
|
+
exportTimeout: Config.option(Config.int("OTEL_METRIC_EXPORT_TIMEOUT")),
|
|
509
|
+
exportInterval: Config.option(Config.int("OTEL_METRIC_EXPORT_INTERVAL")),
|
|
510
|
+
temporalityPreference: Config.option(
|
|
511
|
+
Config.literals(["delta", "cumulative"], "OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE")
|
|
512
|
+
)
|
|
513
|
+
})
|
|
514
|
+
|
|
515
|
+
const shutdownTimeout = Option.firstSomeOf([metricsTimeout, baseTimeout, exportTimeout]).pipe(
|
|
516
|
+
Option.map((_) => Duration.millis(_))
|
|
517
|
+
)
|
|
518
|
+
|
|
519
|
+
return layer({
|
|
520
|
+
url: endpoint,
|
|
521
|
+
resource: options?.resource,
|
|
522
|
+
headers: options?.headers ?? (yield* OtlpEnv.headers("METRICS")),
|
|
523
|
+
exportInterval: Option.getOrUndefined(Option.map(exportInterval, (_) => Duration.millis(_))),
|
|
524
|
+
shutdownTimeout: Option.getOrUndefined(shutdownTimeout),
|
|
525
|
+
temporality: Option.getOrUndefined(temporalityPreference)
|
|
526
|
+
})
|
|
527
|
+
}).pipe(Effect.orDie, Layer.unwrap)
|
|
528
|
+
|
|
478
529
|
/**
|
|
479
530
|
* OTLP metrics payload serialized by `OtlpMetrics`.
|
|
480
531
|
*
|
|
@@ -26,10 +26,10 @@
|
|
|
26
26
|
* **Gotchas**
|
|
27
27
|
*
|
|
28
28
|
* `service.name` is required because the signal exporters also use it as the
|
|
29
|
-
* instrumentation scope name.
|
|
30
|
-
*
|
|
31
|
-
* into canonical OTLP attributes instead of being left in the custom
|
|
32
|
-
* map. Unsupported runtime values are formatted as strings.
|
|
29
|
+
* instrumentation scope name. OpenTelemetry environment variables take
|
|
30
|
+
* precedence over explicit options. `service.name` and `service.version` are
|
|
31
|
+
* normalized into canonical OTLP attributes instead of being left in the custom
|
|
32
|
+
* attribute map. Unsupported runtime values are formatted as strings.
|
|
33
33
|
*
|
|
34
34
|
* **See also**
|
|
35
35
|
*
|
|
@@ -102,9 +102,9 @@ export const make = (options: {
|
|
|
102
102
|
*
|
|
103
103
|
* **Details**
|
|
104
104
|
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
* defect.
|
|
105
|
+
* `OTEL_RESOURCE_ATTRIBUTES`, `OTEL_SERVICE_NAME`, and
|
|
106
|
+
* `OTEL_SERVICE_VERSION` override explicit options; missing required
|
|
107
|
+
* configuration is converted to a defect.
|
|
108
108
|
*
|
|
109
109
|
* @category constructors
|
|
110
110
|
* @since 4.0.0
|
|
@@ -120,19 +120,30 @@ export const fromConfig: (
|
|
|
120
120
|
readonly serviceVersion?: string | undefined
|
|
121
121
|
readonly attributes?: Record<string, unknown> | undefined
|
|
122
122
|
}) {
|
|
123
|
+
const env = yield* Config.schema(
|
|
124
|
+
Schema.UndefinedOr(Config.Record(Schema.String, Schema.String)),
|
|
125
|
+
"OTEL_RESOURCE_ATTRIBUTES"
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
const serviceName = (yield* Config.schema(Schema.UndefinedOr(Schema.String), "OTEL_SERVICE_NAME"))
|
|
129
|
+
?? env?.["service.name"] as string | undefined
|
|
130
|
+
?? options?.attributes?.["service.name"] as string | undefined
|
|
131
|
+
?? options?.serviceName
|
|
132
|
+
?? (yield* Config.string("OTEL_SERVICE_NAME"))
|
|
133
|
+
|
|
134
|
+
const serviceVersion = (yield* Config.schema(Schema.UndefinedOr(Schema.String), "OTEL_SERVICE_VERSION"))
|
|
135
|
+
?? env?.["service.version"] as string | undefined
|
|
136
|
+
?? options?.attributes?.["service.version"] as string | undefined
|
|
137
|
+
?? options?.serviceVersion
|
|
138
|
+
|
|
123
139
|
const attributes = {
|
|
124
|
-
...
|
|
125
|
-
|
|
126
|
-
"OTEL_RESOURCE_ATTRIBUTES"
|
|
127
|
-
)),
|
|
128
|
-
...options?.attributes
|
|
140
|
+
...options?.attributes,
|
|
141
|
+
...env
|
|
129
142
|
}
|
|
130
|
-
|
|
131
|
-
(yield* Config.schema(Schema.String, "OTEL_SERVICE_NAME"))
|
|
143
|
+
|
|
132
144
|
delete attributes["service.name"]
|
|
133
|
-
const serviceVersion = options?.serviceVersion ?? attributes["service.version"] as string ??
|
|
134
|
-
(yield* Config.schema(Schema.UndefinedOr(Schema.String), "OTEL_SERVICE_VERSION"))
|
|
135
145
|
delete attributes["service.version"]
|
|
146
|
+
|
|
136
147
|
return make({
|
|
137
148
|
serviceName,
|
|
138
149
|
serviceVersion,
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
* @since 4.0.0
|
|
25
25
|
*/
|
|
26
26
|
import * as Cause from "../../Cause.ts"
|
|
27
|
+
import * as Config from "../../Config.ts"
|
|
27
28
|
import type * as Context from "../../Context.ts"
|
|
28
29
|
import * as Duration from "../../Duration.ts"
|
|
29
30
|
import * as Effect from "../../Effect.ts"
|
|
@@ -36,6 +37,7 @@ import * as Tracer from "../../Tracer.ts"
|
|
|
36
37
|
import type { ExtractTag, Mutable } from "../../Types.ts"
|
|
37
38
|
import type * as Headers from "../http/Headers.ts"
|
|
38
39
|
import type * as HttpClient from "../http/HttpClient.ts"
|
|
40
|
+
import * as OtlpEnv from "./internal/otlpEnv.ts"
|
|
39
41
|
import * as Exporter from "./OtlpExporter.ts"
|
|
40
42
|
import type { KeyValue, Resource } from "./OtlpResource.ts"
|
|
41
43
|
import { entriesToAttributes } from "./OtlpResource.ts"
|
|
@@ -147,6 +149,56 @@ export const layer: (options: {
|
|
|
147
149
|
readonly shutdownTimeout?: Duration.Input | undefined
|
|
148
150
|
}) => Layer.Layer<never, never, OtlpSerialization | HttpClient.HttpClient> = flow(make, Layer.effect(Tracer.Tracer))
|
|
149
151
|
|
|
152
|
+
/**
|
|
153
|
+
* Creates an OTLP traces layer from OpenTelemetry configuration.
|
|
154
|
+
*
|
|
155
|
+
* @category layers
|
|
156
|
+
* @since 4.0.0
|
|
157
|
+
*/
|
|
158
|
+
export const layerFromConfig = (options?: {
|
|
159
|
+
readonly resource?: {
|
|
160
|
+
readonly serviceName?: string | undefined
|
|
161
|
+
readonly serviceVersion?: string | undefined
|
|
162
|
+
readonly attributes?: Record<string, unknown>
|
|
163
|
+
} | undefined
|
|
164
|
+
readonly headers?: Headers.Input | undefined
|
|
165
|
+
readonly context?: (<X>(primitive: Tracer.EffectPrimitive<X>, span: Tracer.AnySpan) => X) | undefined
|
|
166
|
+
}): Layer.Layer<never, never, HttpClient.HttpClient | OtlpSerialization> =>
|
|
167
|
+
Effect.gen(function*() {
|
|
168
|
+
const { disabled, endpoint, exporters } = yield* Config.all({
|
|
169
|
+
disabled: Config.boolean("OTEL_SDK_DISABLED").pipe(Config.withDefault(false)),
|
|
170
|
+
endpoint: OtlpEnv.endpoint("TRACES"),
|
|
171
|
+
exporters: OtlpEnv.exporters("TRACES")
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
if (disabled || !endpoint || !exporters.includes("otlp")) {
|
|
175
|
+
return Layer.empty
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const { baseTimeout, tracesTimeout, exportTimeout, scheduleDelay, maxBatchSize } = yield* Config.all({
|
|
179
|
+
baseTimeout: Config.option(Config.int("OTEL_EXPORTER_OTLP_TIMEOUT")),
|
|
180
|
+
tracesTimeout: Config.option(Config.int("OTEL_EXPORTER_OTLP_TRACES_TIMEOUT")),
|
|
181
|
+
exportTimeout: Config.option(Config.int("OTEL_BSP_EXPORT_TIMEOUT")),
|
|
182
|
+
scheduleDelay: Config.option(Config.int("OTEL_BSP_SCHEDULE_DELAY")),
|
|
183
|
+
maxBatchSize: Config.option(Config.int("OTEL_BSP_MAX_EXPORT_BATCH_SIZE"))
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
const shutdownTimeout = Option.firstSomeOf([tracesTimeout, baseTimeout, exportTimeout]).pipe(
|
|
187
|
+
Option.map((_) => Duration.millis(_))
|
|
188
|
+
)
|
|
189
|
+
const exportInterval = Option.map(scheduleDelay, (_) => Duration.millis(_))
|
|
190
|
+
|
|
191
|
+
return layer({
|
|
192
|
+
url: endpoint,
|
|
193
|
+
resource: options?.resource,
|
|
194
|
+
headers: options?.headers ?? (yield* OtlpEnv.headers("TRACES")),
|
|
195
|
+
exportInterval: Option.getOrUndefined(exportInterval),
|
|
196
|
+
maxBatchSize: Option.getOrUndefined(maxBatchSize),
|
|
197
|
+
context: options?.context,
|
|
198
|
+
shutdownTimeout: Option.getOrUndefined(shutdownTimeout)
|
|
199
|
+
})
|
|
200
|
+
}).pipe(Effect.orDie, Layer.unwrap)
|
|
201
|
+
|
|
150
202
|
// internal
|
|
151
203
|
|
|
152
204
|
interface SpanImpl extends Tracer.Span {
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import * as Config from "../../../Config.ts"
|
|
2
|
+
import * as Effect from "../../../Effect.ts"
|
|
3
|
+
import * as Option from "../../../Option.ts"
|
|
4
|
+
import * as Schema from "../../../Schema.ts"
|
|
5
|
+
import * as SchemaGetter from "../../../SchemaGetter.ts"
|
|
6
|
+
import * as SchemaTransformation from "../../../SchemaTransformation.ts"
|
|
7
|
+
import * as HttpClientRequest from "../../http/HttpClientRequest.ts"
|
|
8
|
+
|
|
9
|
+
export type Signal = "LOGS" | "METRICS" | "TRACES"
|
|
10
|
+
|
|
11
|
+
const ExporterList = Config.Array(
|
|
12
|
+
Schema.String.pipe(
|
|
13
|
+
Schema.decode(SchemaTransformation.trim()),
|
|
14
|
+
Schema.decode(SchemaTransformation.toLowerCase())
|
|
15
|
+
)
|
|
16
|
+
).pipe(
|
|
17
|
+
Schema.decode({
|
|
18
|
+
decode: SchemaGetter.transform((_: ReadonlyArray<string>) => _.filter((_) => _ !== "")),
|
|
19
|
+
encode: SchemaGetter.passthrough()
|
|
20
|
+
})
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
const HeadersRecord = Config.Record(Schema.String, Schema.String)
|
|
24
|
+
|
|
25
|
+
export const headers = (signal: Signal) =>
|
|
26
|
+
Config.make((provider) =>
|
|
27
|
+
Effect.gen(function*() {
|
|
28
|
+
const headers = yield* Config.option(Config.schema(HeadersRecord, `OTEL_EXPORTER_OTLP_${signal}_HEADERS`)).parse(
|
|
29
|
+
provider
|
|
30
|
+
)
|
|
31
|
+
if (Option.isSome(headers)) {
|
|
32
|
+
return headers.value
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const fallback = yield* Config.option(Config.schema(HeadersRecord, "OTEL_EXPORTER_OTLP_HEADERS")).parse(provider)
|
|
36
|
+
return Option.getOrUndefined(fallback)
|
|
37
|
+
})
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
export const endpoint = (signal: Signal) =>
|
|
41
|
+
Config.make((provider) =>
|
|
42
|
+
Effect.gen(function*() {
|
|
43
|
+
const endpoint = yield* Config.option(Config.string(`OTEL_EXPORTER_OTLP_${signal}_ENDPOINT`)).parse(provider)
|
|
44
|
+
if (Option.isSome(endpoint)) {
|
|
45
|
+
return endpoint.value
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const fallback = yield* Config.option(Config.string("OTEL_EXPORTER_OTLP_ENDPOINT")).parse(provider)
|
|
49
|
+
return Option.isSome(fallback) && fallback.value !== ""
|
|
50
|
+
? HttpClientRequest.appendUrl(HttpClientRequest.get(fallback.value), `/v1/${signal.toLowerCase()}`).url
|
|
51
|
+
: undefined
|
|
52
|
+
})
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
export const exporters = (signal: Signal) =>
|
|
56
|
+
Config.option(Config.schema(ExporterList, `OTEL_${signal}_EXPORTER`)).pipe(
|
|
57
|
+
Config.map(Option.getOrElse<ReadonlyArray<string>>(() => []))
|
|
58
|
+
)
|