effect 4.0.0-beta.76 → 4.0.0-beta.78
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/SchemaTransformation.js +1 -1
- package/dist/SchemaTransformation.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 +45 -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 +16 -0
- package/dist/unstable/observability/internal/otlpEnv.js.map +1 -0
- package/dist/unstable/persistence/RateLimiter.d.ts.map +1 -1
- package/dist/unstable/persistence/RateLimiter.js +5 -4
- package/dist/unstable/persistence/RateLimiter.js.map +1 -1
- package/dist/unstable/persistence/Redis.d.ts.map +1 -1
- package/dist/unstable/persistence/Redis.js +4 -1
- package/dist/unstable/persistence/Redis.js.map +1 -1
- package/package.json +1 -1
- package/src/Config.ts +44 -0
- package/src/SchemaTransformation.ts +1 -1
- package/src/unstable/observability/Otlp.ts +36 -0
- package/src/unstable/observability/OtlpLogger.ts +56 -1
- package/src/unstable/observability/OtlpMetrics.ts +55 -0
- package/src/unstable/observability/OtlpResource.ts +27 -16
- package/src/unstable/observability/OtlpTracer.ts +55 -0
- package/src/unstable/observability/internal/otlpEnv.ts +39 -0
- package/src/unstable/persistence/RateLimiter.ts +6 -3
- package/src/unstable/persistence/Redis.ts +11 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Redis.js","names":["Cache","Context","Effect","Equal","constant","identity","Hash","Schema","Redis","Service","make","fnUntraced","options","scriptCache","lookup","script","send","lua","capacity","Number","POSITIVE_INFINITY","eval_","params","
|
|
1
|
+
{"version":3,"file":"Redis.js","names":["Cache","Context","Effect","Equal","constant","identity","Hash","Schema","Redis","Service","make","fnUntraced","options","scriptCache","lookup","script","send","lua","capacity","Number","POSITIVE_INFINITY","eval_","params","evalSha","sha","numberOfKeys","toString","map","param","String","get","pipe","flatMap","catchIf","error","cause","includes","refresh","eval","ErrorTypeId","RedisError","ErrorClass","_tag","tag","Defect","ScriptTypeId","ScriptProto","result","withReturnType","symbol","that","random","f","Object","assign","create"],"sources":["../../../src/unstable/persistence/Redis.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
|
package/package.json
CHANGED
package/src/Config.ts
CHANGED
|
@@ -82,6 +82,7 @@ import * as Predicate from "./Predicate.ts"
|
|
|
82
82
|
import * as Rec from "./Record.ts"
|
|
83
83
|
import * as Schema from "./Schema.ts"
|
|
84
84
|
import * as SchemaAST from "./SchemaAST.ts"
|
|
85
|
+
import * as SchemaGetter from "./SchemaGetter.ts"
|
|
85
86
|
import * as SchemaIssue from "./SchemaIssue.ts"
|
|
86
87
|
import * as SchemaParser from "./SchemaParser.ts"
|
|
87
88
|
import * as SchemaTransformation from "./SchemaTransformation.ts"
|
|
@@ -1121,6 +1122,49 @@ export const Record = <K extends Schema.Record.Key, V extends Schema.Top>(key: K
|
|
|
1121
1122
|
return Schema.Union([record, recordString])
|
|
1122
1123
|
}
|
|
1123
1124
|
|
|
1125
|
+
/**
|
|
1126
|
+
* @category schemas
|
|
1127
|
+
* @since 4.0.0
|
|
1128
|
+
*/
|
|
1129
|
+
const ArrayConfig = <V extends Schema.Top>(value: V, options?: {
|
|
1130
|
+
readonly separator?: string | undefined
|
|
1131
|
+
}) => {
|
|
1132
|
+
const array = Schema.Array(value)
|
|
1133
|
+
const separator = options?.separator ?? ","
|
|
1134
|
+
const arrayString = Schema.String.pipe(
|
|
1135
|
+
Schema.decodeTo(
|
|
1136
|
+
Schema.Array(Schema.String),
|
|
1137
|
+
{
|
|
1138
|
+
decode: SchemaGetter.split(options),
|
|
1139
|
+
encode: SchemaGetter.transform((input: ReadonlyArray<string>) => input.join(separator))
|
|
1140
|
+
}
|
|
1141
|
+
),
|
|
1142
|
+
Schema.decodeTo(array)
|
|
1143
|
+
)
|
|
1144
|
+
|
|
1145
|
+
return Schema.Union([arrayString, array])
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
export {
|
|
1149
|
+
/**
|
|
1150
|
+
* Schema for array types that can also be parsed from a flat separated string.
|
|
1151
|
+
*
|
|
1152
|
+
* **When to use**
|
|
1153
|
+
*
|
|
1154
|
+
* Use when reading array values from a single env var, such as comma-separated
|
|
1155
|
+
* exporter names.
|
|
1156
|
+
*
|
|
1157
|
+
* **Details**
|
|
1158
|
+
*
|
|
1159
|
+
* Accepts either a JSON-like array from the provider or a flat string like
|
|
1160
|
+
* `"a,b,c"`. The `separator` defaults to `","` and can be customized.
|
|
1161
|
+
*
|
|
1162
|
+
* @category schemas
|
|
1163
|
+
* @since 4.0.0
|
|
1164
|
+
*/
|
|
1165
|
+
ArrayConfig as Array
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1124
1168
|
// -----------------------------------------------------------------------------
|
|
1125
1169
|
// constructors
|
|
1126
1170
|
// -----------------------------------------------------------------------------
|
|
@@ -1112,7 +1112,7 @@ const encodeJsonError = (
|
|
|
1112
1112
|
): JsonError => {
|
|
1113
1113
|
const encoded: JsonError = {
|
|
1114
1114
|
name: input.name,
|
|
1115
|
-
message: input.message
|
|
1115
|
+
message: typeof input.message === "string" ? input.message : ""
|
|
1116
1116
|
}
|
|
1117
1117
|
if (options?.includeStack && typeof input.stack === "string") {
|
|
1118
1118
|
encoded.stack = input.stack
|
|
@@ -110,6 +110,42 @@ export const layer = (options: {
|
|
|
110
110
|
)
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
+
/**
|
|
114
|
+
* Creates a combined OTLP layer for logs, metrics, and traces from
|
|
115
|
+
* OpenTelemetry configuration.
|
|
116
|
+
*
|
|
117
|
+
* @category layers
|
|
118
|
+
* @since 4.0.0
|
|
119
|
+
*/
|
|
120
|
+
export const layerFromConfig = (options?: {
|
|
121
|
+
readonly resource?: {
|
|
122
|
+
readonly serviceName?: string | undefined
|
|
123
|
+
readonly serviceVersion?: string | undefined
|
|
124
|
+
readonly attributes?: Record<string, unknown>
|
|
125
|
+
} | undefined
|
|
126
|
+
readonly headers?: Headers.Input | undefined
|
|
127
|
+
readonly tracerContext?: (<X>(primitive: Tracer.EffectPrimitive<X>, span: Tracer.AnySpan) => X) | undefined
|
|
128
|
+
readonly loggerExcludeLogSpans?: boolean | undefined
|
|
129
|
+
readonly loggerMergeWithExisting?: boolean | undefined
|
|
130
|
+
}): Layer.Layer<never, never, HttpClient.HttpClient | OtlpSerialization.OtlpSerialization> =>
|
|
131
|
+
Layer.mergeAll(
|
|
132
|
+
OtlpLogger.layerFromConfig({
|
|
133
|
+
resource: options?.resource,
|
|
134
|
+
headers: options?.headers,
|
|
135
|
+
excludeLogSpans: options?.loggerExcludeLogSpans,
|
|
136
|
+
mergeWithExisting: options?.loggerMergeWithExisting
|
|
137
|
+
}),
|
|
138
|
+
OtlpMetrics.layerFromConfig({
|
|
139
|
+
resource: options?.resource,
|
|
140
|
+
headers: options?.headers
|
|
141
|
+
}),
|
|
142
|
+
OtlpTracer.layerFromConfig({
|
|
143
|
+
resource: options?.resource,
|
|
144
|
+
headers: options?.headers,
|
|
145
|
+
context: options?.tracerContext
|
|
146
|
+
})
|
|
147
|
+
)
|
|
148
|
+
|
|
113
149
|
/**
|
|
114
150
|
* Creates the combined OTLP logs, metrics, and traces layer using JSON
|
|
115
151
|
* serialization.
|
|
@@ -37,15 +37,18 @@
|
|
|
37
37
|
import * as Arr from "../../Array.ts"
|
|
38
38
|
import * as Cause from "../../Cause.ts"
|
|
39
39
|
import { Clock } from "../../Clock.ts"
|
|
40
|
+
import * as Config from "../../Config.ts"
|
|
40
41
|
import * as Duration from "../../Duration.ts"
|
|
41
42
|
import * as Effect from "../../Effect.ts"
|
|
42
|
-
import
|
|
43
|
+
import * as Layer from "../../Layer.ts"
|
|
43
44
|
import * as Logger from "../../Logger.ts"
|
|
44
45
|
import type * as LogLevel from "../../LogLevel.ts"
|
|
46
|
+
import * as Option from "../../Option.ts"
|
|
45
47
|
import { CurrentLogAnnotations, CurrentLogSpans } from "../../References.ts"
|
|
46
48
|
import type * as Scope from "../../Scope.ts"
|
|
47
49
|
import type * as Headers from "../http/Headers.ts"
|
|
48
50
|
import type * as HttpClient from "../http/HttpClient.ts"
|
|
51
|
+
import * as OtlpEnv from "./internal/otlpEnv.ts"
|
|
49
52
|
import * as Exporter from "./OtlpExporter.ts"
|
|
50
53
|
import type { AnyValue, Fixed64, KeyValue, Resource } from "./OtlpResource.ts"
|
|
51
54
|
import * as OtlpResource from "./OtlpResource.ts"
|
|
@@ -144,6 +147,58 @@ export const layer = (options: {
|
|
|
144
147
|
mergeWithExisting: options.mergeWithExisting ?? true
|
|
145
148
|
})
|
|
146
149
|
|
|
150
|
+
/**
|
|
151
|
+
* Creates an OTLP logs layer from OpenTelemetry configuration.
|
|
152
|
+
*
|
|
153
|
+
* @category layers
|
|
154
|
+
* @since 4.0.0
|
|
155
|
+
*/
|
|
156
|
+
export const layerFromConfig = (options?: {
|
|
157
|
+
readonly resource?: {
|
|
158
|
+
readonly serviceName?: string | undefined
|
|
159
|
+
readonly serviceVersion?: string | undefined
|
|
160
|
+
readonly attributes?: Record<string, unknown>
|
|
161
|
+
} | undefined
|
|
162
|
+
readonly headers?: Headers.Input | undefined
|
|
163
|
+
readonly excludeLogSpans?: boolean | undefined
|
|
164
|
+
readonly mergeWithExisting?: boolean | undefined
|
|
165
|
+
}): Layer.Layer<never, never, HttpClient.HttpClient | OtlpSerialization> =>
|
|
166
|
+
Effect.gen(function*() {
|
|
167
|
+
const { disabled, endpoint, exporters } = yield* Config.all({
|
|
168
|
+
disabled: Config.boolean("OTEL_SDK_DISABLED").pipe(Config.withDefault(false)),
|
|
169
|
+
endpoint: OtlpEnv.endpoint("LOGS"),
|
|
170
|
+
exporters: OtlpEnv.exporters("LOGS")
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
if (disabled || !endpoint || !exporters.includes("otlp")) {
|
|
174
|
+
return Layer.empty
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const { baseTimeout, logsTimeout, exportTimeout, scheduleDelay, maxBatchSize } = yield* Config.all({
|
|
178
|
+
baseTimeout: Config.option(Config.int("OTEL_EXPORTER_OTLP_TIMEOUT")),
|
|
179
|
+
logsTimeout: Config.option(Config.int("OTEL_EXPORTER_OTLP_LOGS_TIMEOUT")),
|
|
180
|
+
exportTimeout: Config.option(Config.int("OTEL_BLRP_EXPORT_TIMEOUT")),
|
|
181
|
+
scheduleDelay: Config.option(Config.int("OTEL_BLRP_SCHEDULE_DELAY")),
|
|
182
|
+
maxBatchSize: Config.option(Config.int("OTEL_BLRP_MAX_EXPORT_BATCH_SIZE"))
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
const shutdownTimeout = Option.firstSomeOf([logsTimeout, baseTimeout, exportTimeout]).pipe(
|
|
186
|
+
Option.map((_) => Duration.millis(_))
|
|
187
|
+
)
|
|
188
|
+
const exportInterval = Option.map(scheduleDelay, (_) => Duration.millis(_))
|
|
189
|
+
|
|
190
|
+
return layer({
|
|
191
|
+
url: endpoint.toString(),
|
|
192
|
+
resource: options?.resource,
|
|
193
|
+
headers: options?.headers ?? (yield* OtlpEnv.headers("LOGS")),
|
|
194
|
+
exportInterval: Option.getOrUndefined(exportInterval),
|
|
195
|
+
maxBatchSize: Option.getOrUndefined(maxBatchSize),
|
|
196
|
+
shutdownTimeout: Option.getOrUndefined(shutdownTimeout),
|
|
197
|
+
excludeLogSpans: options?.excludeLogSpans,
|
|
198
|
+
mergeWithExisting: options?.mergeWithExisting
|
|
199
|
+
})
|
|
200
|
+
}).pipe(Effect.orDie, Layer.unwrap)
|
|
201
|
+
|
|
147
202
|
/**
|
|
148
203
|
* OTLP logs payload serialized by `OtlpLogger`.
|
|
149
204
|
*
|
|
@@ -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,58 @@ 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(
|
|
510
|
+
Config.int("OTEL_METRIC_EXPORT_INTERVAL").pipe(
|
|
511
|
+
Config.map(Duration.millis)
|
|
512
|
+
)
|
|
513
|
+
),
|
|
514
|
+
temporalityPreference: Config.option(
|
|
515
|
+
Config.literals(["delta", "cumulative"], "OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE")
|
|
516
|
+
)
|
|
517
|
+
})
|
|
518
|
+
|
|
519
|
+
const shutdownTimeout = Option.firstSomeOf([metricsTimeout, baseTimeout, exportTimeout]).pipe(
|
|
520
|
+
Option.map((_) => Duration.millis(_))
|
|
521
|
+
)
|
|
522
|
+
|
|
523
|
+
return layer({
|
|
524
|
+
url: endpoint.toString(),
|
|
525
|
+
resource: options?.resource,
|
|
526
|
+
headers: options?.headers ?? (yield* OtlpEnv.headers("METRICS")),
|
|
527
|
+
exportInterval: Option.getOrUndefined(exportInterval),
|
|
528
|
+
shutdownTimeout: Option.getOrUndefined(shutdownTimeout),
|
|
529
|
+
temporality: Option.getOrUndefined(temporalityPreference)
|
|
530
|
+
})
|
|
531
|
+
}).pipe(Effect.orDie, Layer.unwrap)
|
|
532
|
+
|
|
478
533
|
/**
|
|
479
534
|
* OTLP metrics payload serialized by `OtlpMetrics`.
|
|
480
535
|
*
|
|
@@ -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,59 @@ 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(
|
|
183
|
+
Config.int("OTEL_BSP_SCHEDULE_DELAY").pipe(
|
|
184
|
+
Config.map(Duration.millis)
|
|
185
|
+
)
|
|
186
|
+
),
|
|
187
|
+
maxBatchSize: Config.option(Config.int("OTEL_BSP_MAX_EXPORT_BATCH_SIZE"))
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
const shutdownTimeout = Option.firstSomeOf([tracesTimeout, baseTimeout, exportTimeout]).pipe(
|
|
191
|
+
Option.map((_) => Duration.millis(_))
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
return layer({
|
|
195
|
+
url: endpoint.toString(),
|
|
196
|
+
resource: options?.resource,
|
|
197
|
+
headers: options?.headers ?? (yield* OtlpEnv.headers("TRACES")),
|
|
198
|
+
exportInterval: Option.getOrUndefined(scheduleDelay),
|
|
199
|
+
maxBatchSize: Option.getOrUndefined(maxBatchSize),
|
|
200
|
+
context: options?.context,
|
|
201
|
+
shutdownTimeout: Option.getOrUndefined(shutdownTimeout)
|
|
202
|
+
})
|
|
203
|
+
}).pipe(Effect.orDie, Layer.unwrap)
|
|
204
|
+
|
|
150
205
|
// internal
|
|
151
206
|
|
|
152
207
|
interface SpanImpl extends Tracer.Span {
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import * as Config from "../../../Config.ts"
|
|
2
|
+
import * as Schema from "../../../Schema.ts"
|
|
3
|
+
import * as SchemaGetter from "../../../SchemaGetter.ts"
|
|
4
|
+
|
|
5
|
+
export type Signal = "LOGS" | "METRICS" | "TRACES"
|
|
6
|
+
|
|
7
|
+
const ExporterList = Config.Array(Schema.String).pipe(
|
|
8
|
+
Schema.decode({
|
|
9
|
+
decode: SchemaGetter.transform((_) => _.map((_) => _.toLowerCase().trim()).filter((_) => _ !== "")),
|
|
10
|
+
encode: SchemaGetter.passthrough()
|
|
11
|
+
})
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
const HeadersRecord = Config.Record(Schema.String, Schema.String)
|
|
15
|
+
|
|
16
|
+
export const headers = (signal: Signal) =>
|
|
17
|
+
Config.schema(HeadersRecord, `OTEL_EXPORTER_OTLP_${signal}_HEADERS`).pipe(
|
|
18
|
+
Config.orElse(() => Config.schema(HeadersRecord, "OTEL_EXPORTER_OTLP_HEADERS")),
|
|
19
|
+
Config.withDefault(undefined)
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
export const endpoint = (signal: Signal) =>
|
|
23
|
+
Config.url(`OTEL_EXPORTER_OTLP_${signal}_ENDPOINT`).pipe(
|
|
24
|
+
Config.orElse(() =>
|
|
25
|
+
Config.url("OTEL_EXPORTER_OTLP_ENDPOINT").pipe(
|
|
26
|
+
Config.map((url) => {
|
|
27
|
+
const slash = url.pathname.endsWith("/") ? "" : "/"
|
|
28
|
+
url.pathname += `${slash}v1/${signal.toLowerCase()}`
|
|
29
|
+
return url
|
|
30
|
+
})
|
|
31
|
+
)
|
|
32
|
+
),
|
|
33
|
+
Config.withDefault(undefined)
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
export const exporters = (signal: Signal) =>
|
|
37
|
+
Config.schema(ExporterList, `OTEL_${signal}_EXPORTER`).pipe(
|
|
38
|
+
Config.withDefault<ReadonlyArray<string>>([])
|
|
39
|
+
)
|
|
@@ -630,11 +630,13 @@ export const makeStoreRedis = Effect.fnUntraced(function*(
|
|
|
630
630
|
},
|
|
631
631
|
tokenBucket(options) {
|
|
632
632
|
const key = `${prefix}${options.key}`
|
|
633
|
+
const lastRefillKey = `${key}:refill`
|
|
633
634
|
const refillMillis = Duration.toMillis(options.refillRate)
|
|
634
635
|
return Effect.clockWith((clock) =>
|
|
635
636
|
Effect.mapError(
|
|
636
637
|
tokenBucket(
|
|
637
638
|
key,
|
|
639
|
+
lastRefillKey,
|
|
638
640
|
options.tokens,
|
|
639
641
|
refillMillis,
|
|
640
642
|
options.limit,
|
|
@@ -687,17 +689,18 @@ return { next, nextpttl }
|
|
|
687
689
|
const tokenBucketScript = Redis.script(
|
|
688
690
|
(
|
|
689
691
|
key: string,
|
|
692
|
+
lastRefillKey: string,
|
|
690
693
|
tokens: number,
|
|
691
694
|
refillMillis: number,
|
|
692
695
|
limit: number,
|
|
693
696
|
now: number,
|
|
694
697
|
overflow: 0 | 1
|
|
695
|
-
) => [key, tokens, refillMillis, limit, now, overflow],
|
|
698
|
+
) => [key, lastRefillKey, tokens, refillMillis, limit, now, overflow],
|
|
696
699
|
{
|
|
697
|
-
numberOfKeys:
|
|
700
|
+
numberOfKeys: 2,
|
|
698
701
|
lua: `
|
|
699
702
|
local key = KEYS[1]
|
|
700
|
-
local last_refill_key =
|
|
703
|
+
local last_refill_key = KEYS[2]
|
|
701
704
|
local tokens = tonumber(ARGV[1])
|
|
702
705
|
local refill_ms = tonumber(ARGV[2])
|
|
703
706
|
local limit = tonumber(ARGV[3])
|
|
@@ -89,14 +89,22 @@ export const make = Effect.fnUntraced(function*(
|
|
|
89
89
|
>(
|
|
90
90
|
script: Script<Config>
|
|
91
91
|
) =>
|
|
92
|
-
(...params: Config["params"]): Effect.Effect<Config["result"], RedisError> =>
|
|
93
|
-
|
|
92
|
+
(...params: Config["params"]): Effect.Effect<Config["result"], RedisError> => {
|
|
93
|
+
const evalSha = (sha: string) =>
|
|
94
94
|
options.send<Config["result"]>(
|
|
95
95
|
"EVALSHA",
|
|
96
96
|
sha,
|
|
97
97
|
script.numberOfKeys(...params).toString(),
|
|
98
98
|
...script.params(...params).map((param) => String(param))
|
|
99
|
-
)
|
|
99
|
+
)
|
|
100
|
+
return Cache.get(scriptCache, script).pipe(
|
|
101
|
+
Effect.flatMap(evalSha),
|
|
102
|
+
Effect.catchIf(
|
|
103
|
+
(error) => String(error.cause).includes("NOSCRIPT"),
|
|
104
|
+
() => Cache.refresh(scriptCache, script).pipe(Effect.flatMap(evalSha))
|
|
105
|
+
)
|
|
106
|
+
)
|
|
107
|
+
}
|
|
100
108
|
|
|
101
109
|
return identity<Redis["Service"]>({
|
|
102
110
|
send: options.send,
|