1/**
2 * Configures OpenTelemetry Protocol (OTLP) HTTP export for Effect telemetry.
3 *
4 * This module installs the OTLP logger, metrics exporter, and tracer exporter
5 * from one shared configuration. Use it when an application sends logs, metrics,
6 * and traces to the same OpenTelemetry Collector, vendor OTLP endpoint, or local
7 * development collector.
8 *
9 * @stability unstable
10 * @since 4.0.0
11 */
12import type * as Duration from "../Duration.ts"
13import { flow } from "../Function.ts"
14import type * as Headers from "../http/Headers.ts"
15import type * as HttpClient from "../http/HttpClient.ts"
16import * as HttpClientRequest from "../http/HttpClientRequest.ts"
17import * as Layer from "../Layer.ts"
18import type * as Tracer from "../Tracer.ts"
19import * as OtlpLogger from "./OtlpLogger.ts"
20import type { AggregationTemporality } from "./OtlpMetrics.ts"
21import * as OtlpMetrics from "./OtlpMetrics.ts"
22import * as OtlpSerialization from "./OtlpSerialization.ts"
23import * as OtlpTracer from "./OtlpTracer.ts"
24
25/**
26 * Creates a combined OTLP layer for logs, metrics, and traces.
27 *
28 * **Details**
29 *
30 * The layer sends data to `/v1/logs`, `/v1/metrics`, and `/v1/traces` below
31 * `baseUrl` and requires an `OtlpSerialization` implementation.
32 *
33 * @stability unstable
34 * @category layers
35 * @since 4.0.0
36 */
37export const layer = (options: {
38 readonly baseUrl: string
39 readonly resource?: {
40 readonly serviceName?: string | undefined
41 readonly serviceVersion?: string | undefined
42 readonly attributes?: Record<string, unknown>
43 } | undefined
44 readonly headers?: Headers.Input | undefined
45 readonly maxBatchSize?: number | undefined
46 readonly tracerContext?: (<X>(primitive: Tracer.EffectPrimitive<X>, span: Tracer.AnySpan) => X) | undefined
47 readonly loggerExportInterval?: Duration.Input | undefined
48 readonly loggerExcludeLogSpans?: boolean | undefined
49 readonly loggerMergeWithExisting?: boolean | undefined
50 readonly metricsExportInterval?: Duration.Input | undefined
51 readonly metricsTemporality?: AggregationTemporality | undefined
52 readonly tracerExportInterval?: Duration.Input | undefined
53 readonly shutdownTimeout?: Duration.Input | undefined
54}): Layer.Layer<never, never, HttpClient.HttpClient | OtlpSerialization.OtlpSerialization> => {
55 const base = HttpClientRequest.get(options.baseUrl)
56 const url = (path: string) => HttpClientRequest.appendUrl(base, path).url
57 return Layer.mergeAll(
58 OtlpLogger.layer({
59 url: url("/v1/logs"),
60 resource: options.resource,
61 headers: options.headers,
62 exportInterval: options.loggerExportInterval,
63 maxBatchSize: options.maxBatchSize,
64 shutdownTimeout: options.shutdownTimeout,
65 excludeLogSpans: options.loggerExcludeLogSpans,
66 mergeWithExisting: options.loggerMergeWithExisting
67 }),
68 OtlpMetrics.layer({
69 url: url("/v1/metrics"),
70 resource: options.resource,
71 headers: options.headers,
72 exportInterval: options.metricsExportInterval,
73 shutdownTimeout: options.shutdownTimeout,
74 temporality: options.metricsTemporality
75 }),
76 OtlpTracer.layer({
77 url: url("/v1/traces"),
78 resource: options.resource,
79 headers: options.headers,
80 exportInterval: options.tracerExportInterval,
81 maxBatchSize: options.maxBatchSize,
82 context: options.tracerContext,
83 shutdownTimeout: options.shutdownTimeout
84 })
85 )
86}
87
88/**
89 * Creates a combined OTLP layer for logs, metrics, and traces from
90 * OpenTelemetry configuration.
91 *
92 * @stability unstable
93 * @category layers
94 * @since 4.0.0
95 */
96export const layerFromConfig = (options?: {
97 readonly resource?: {
98 readonly serviceName?: string | undefined
99 readonly serviceVersion?: string | undefined
100 readonly attributes?: Record<string, unknown>
101 } | undefined
102 readonly headers?: Headers.Input | undefined
103 readonly tracerContext?: (<X>(primitive: Tracer.EffectPrimitive<X>, span: Tracer.AnySpan) => X) | undefined
104 readonly loggerExcludeLogSpans?: boolean | undefined
105 readonly loggerMergeWithExisting?: boolean | undefined
106}): Layer.Layer<never, never, HttpClient.HttpClient | OtlpSerialization.OtlpSerialization> =>
107 Layer.mergeAll(
108 OtlpLogger.layerFromConfig({
109 resource: options?.resource,
110 headers: options?.headers,
111 excludeLogSpans: options?.loggerExcludeLogSpans,
112 mergeWithExisting: options?.loggerMergeWithExisting
113 }),
114 OtlpMetrics.layerFromConfig({
115 resource: options?.resource,
116 headers: options?.headers
117 }),
118 OtlpTracer.layerFromConfig({
119 resource: options?.resource,
120 headers: options?.headers,
121 context: options?.tracerContext
122 })
123 )
124
125/**
126 * Creates the combined OTLP logs, metrics, and traces layer using JSON
127 * serialization.
128 *
129 * @stability unstable
130 * @category layers
131 * @since 4.0.0
132 */
133export const layerJson: (options: {
134 readonly baseUrl: string
135 readonly resource?: {
136 readonly serviceName?: string | undefined
137 readonly serviceVersion?: string | undefined
138 readonly attributes?: Record<string, unknown>
139 } | undefined
140 readonly headers?: Headers.Input | undefined
141 readonly maxBatchSize?: number | undefined
142 readonly tracerContext?: (<X>(primitive: Tracer.EffectPrimitive<X>, span: Tracer.AnySpan) => X) | undefined
143 readonly loggerExportInterval?: Duration.Input | undefined
144 readonly loggerExcludeLogSpans?: boolean | undefined
145 readonly loggerMergeWithExisting?: boolean | undefined
146 readonly metricsExportInterval?: Duration.Input | undefined
147 readonly metricsTemporality?: AggregationTemporality | undefined
148 readonly tracerExportInterval?: Duration.Input | undefined
149 readonly shutdownTimeout?: Duration.Input | undefined
150}) => Layer.Layer<never, never, HttpClient.HttpClient> = flow(layer, Layer.provide(OtlpSerialization.layerJson))
151
152/**
153 * Creates the combined OTLP logs, metrics, and traces layer using protobuf
154 * serialization.
155 *
156 * @stability unstable
157 * @category layers
158 * @since 4.0.0
159 */
160export const layerProtobuf: (options: {
161 readonly baseUrl: string
162 readonly resource?: {
163 readonly serviceName?: string | undefined
164 readonly serviceVersion?: string | undefined
165 readonly attributes?: Record<string, unknown>
166 } | undefined
167 readonly headers?: Headers.Input | undefined
168 readonly maxBatchSize?: number | undefined
169 readonly tracerContext?: (<X>(primitive: Tracer.EffectPrimitive<X>, span: Tracer.AnySpan) => X) | undefined
170 readonly loggerExportInterval?: Duration.Input | undefined
171 readonly loggerExcludeLogSpans?: boolean | undefined
172 readonly loggerMergeWithExisting?: boolean | undefined
173 readonly metricsExportInterval?: Duration.Input | undefined
174 readonly metricsTemporality?: AggregationTemporality | undefined
175 readonly tracerExportInterval?: Duration.Input | undefined
176 readonly shutdownTimeout?: Duration.Input | undefined
177}) => Layer.Layer<never, never, HttpClient.HttpClient> = flow(layer, Layer.provide(OtlpSerialization.layerProtobuf))