| /** | |
| * Exports Effect log entries over OTLP/HTTP. | |
| * | |
| * The logger turns Effect log entries into OTLP log records and sends them to a | |
| * logs endpoint, such as an OpenTelemetry Collector or vendor OTLP endpoint. It | |
| * includes log levels, messages, annotations, causes, fiber ids, optional log | |
| * spans, and current trace/span ids when they are present. | |
| * | |
| * @since 4.0.0 | |
| */ | |
| import * as Arr from "../../Array.js"; | |
| import * as Cause from "../../Cause.js"; | |
| import { Clock } from "../../Clock.js"; | |
| import * as Config from "../../Config.js"; | |
| import * as Duration from "../../Duration.js"; | |
| import * as Effect from "../../Effect.js"; | |
| import * as Layer from "../../Layer.js"; | |
| import * as Logger from "../../Logger.js"; | |
| import * as Option from "../../Option.js"; | |
| import { CurrentLogAnnotations, CurrentLogSpans } from "../../References.js"; | |
| import * as OtlpEnv from "./internal/otlpEnv.js"; | |
| import * as Exporter from "./OtlpExporter.js"; | |
| import * as OtlpResource from "./OtlpResource.js"; | |
| import { OtlpSerialization } from "./OtlpSerialization.js"; | |
| /** | |
| * Creates an Effect `Logger` that exports log records through OTLP. | |
| * | |
| * **Details** | |
| * | |
| * The logger serializes records with the configured resource, sends them | |
| * through the OTLP exporter, and requires `Scope` so pending records can be | |
| * flushed on shutdown. | |
| * | |
| * @category constructors | |
| * @since 4.0.0 | |
| */ | |
| export const make = /*#__PURE__*/Effect.fnUntraced(function* (options) { | |
| const serialization = yield* OtlpSerialization; | |
| const otelResource = yield* OtlpResource.fromConfig(options.resource); | |
| const scope = { | |
| name: OtlpResource.serviceNameUnsafe(otelResource) | |
| }; | |
| const exporter = yield* Exporter.make({ | |
| label: "OtlpLogger", | |
| url: options.url, | |
| headers: options.headers, | |
| maxBatchSize: options.maxBatchSize ?? 1000, | |
| exportInterval: options.exportInterval ?? Duration.seconds(1), | |
| body: data => serialization.logs({ | |
| resourceLogs: [{ | |
| resource: otelResource, | |
| scopeLogs: [{ | |
| scope, | |
| logRecords: data | |
| }] | |
| }] | |
| }), | |
| shutdownTimeout: options.shutdownTimeout ?? Duration.seconds(3) | |
| }); | |
| const opts = { | |
| excludeLogSpans: options.excludeLogSpans ?? false, | |
| clock: yield* Clock | |
| }; | |
| return Logger.make(options => { | |
| exporter.push(makeLogRecord(options, opts)); | |
| }); | |
| }); | |
| /** | |
| * Layer that installs the OTLP logger created by `make`. | |
| * | |
| * **Details** | |
| * | |
| * By default the OTLP logger is merged with any existing loggers. | |
| * | |
| * @category layers | |
| * @since 4.0.0 | |
| */ | |
| export const layer = options => Logger.layer([make(options)], { | |
| mergeWithExisting: options.mergeWithExisting ?? true | |
| }); | |
| /** | |
| * Creates an OTLP logs layer from OpenTelemetry configuration. | |
| * | |
| * @category layers | |
| * @since 4.0.0 | |
| */ | |
| export const layerFromConfig = options => Effect.gen(function* () { | |
| const { | |
| disabled, | |
| endpoint, | |
| exporters | |
| } = yield* Config.all({ | |
| disabled: Config.boolean("OTEL_SDK_DISABLED").pipe(Config.withDefault(false)), | |
| endpoint: OtlpEnv.endpoint("LOGS"), | |
| exporters: OtlpEnv.exporters("LOGS") | |
| }); | |
| if (disabled || !endpoint || !exporters.includes("otlp")) { | |
| return Layer.empty; | |
| } | |
| const { | |
| baseTimeout, | |
| logsTimeout, | |
| exportTimeout, | |
| scheduleDelay, | |
| maxBatchSize | |
| } = yield* Config.all({ | |
| baseTimeout: Config.option(Config.int("OTEL_EXPORTER_OTLP_TIMEOUT")), | |
| logsTimeout: Config.option(Config.int("OTEL_EXPORTER_OTLP_LOGS_TIMEOUT")), | |
| exportTimeout: Config.option(Config.int("OTEL_BLRP_EXPORT_TIMEOUT")), | |
| scheduleDelay: Config.option(Config.int("OTEL_BLRP_SCHEDULE_DELAY")), | |
| maxBatchSize: Config.option(Config.int("OTEL_BLRP_MAX_EXPORT_BATCH_SIZE")) | |
| }); | |
| const shutdownTimeout = Option.firstSomeOf([logsTimeout, baseTimeout, exportTimeout]).pipe(Option.map(_ => Duration.millis(_))); | |
| const exportInterval = Option.map(scheduleDelay, _ => Duration.millis(_)); | |
| return layer({ | |
| url: endpoint.toString(), | |
| resource: options?.resource, | |
| headers: options?.headers ?? (yield* OtlpEnv.headers("LOGS")), | |
| exportInterval: Option.getOrUndefined(exportInterval), | |
| maxBatchSize: Option.getOrUndefined(maxBatchSize), | |
| shutdownTimeout: Option.getOrUndefined(shutdownTimeout), | |
| excludeLogSpans: options?.excludeLogSpans, | |
| mergeWithExisting: options?.mergeWithExisting | |
| }); | |
| }).pipe(Effect.orDie, Layer.unwrap); | |
| // internal | |
| const makeLogRecord = (options, opts) => { | |
| const now = opts.clock.currentTimeNanosUnsafe(); | |
| const nanosString = now.toString(); | |
| const nowMillis = options.date.getTime(); | |
| const attributes = OtlpResource.entriesToAttributes(Object.entries(options.fiber.getRef(CurrentLogAnnotations))); | |
| attributes.push({ | |
| key: "fiberId", | |
| value: { | |
| intValue: options.fiber.id | |
| } | |
| }); | |
| if (!opts.excludeLogSpans) { | |
| for (const [label, startTime] of options.fiber.getRef(CurrentLogSpans)) { | |
| attributes.push({ | |
| key: `logSpan.${label}`, | |
| value: { | |
| stringValue: `${nowMillis - startTime}ms` | |
| } | |
| }); | |
| } | |
| } | |
| if (options.cause.reasons.length > 0) { | |
| attributes.push({ | |
| key: "log.error", | |
| value: { | |
| stringValue: Cause.pretty(options.cause) | |
| } | |
| }); | |
| } | |
| const message = Arr.ensure(options.message); | |
| const logRecord = { | |
| severityNumber: logLevelToSeverityNumber(options.logLevel), | |
| severityText: options.logLevel, | |
| timeUnixNano: nanosString, | |
| observedTimeUnixNano: nanosString, | |
| attributes, | |
| body: OtlpResource.unknownToAttributeValue(message.length === 1 ? message[0] : message), | |
| droppedAttributesCount: 0 | |
| }; | |
| if (options.fiber.currentSpan) { | |
| logRecord.traceId = options.fiber.currentSpan.traceId; | |
| logRecord.spanId = options.fiber.currentSpan.spanId; | |
| } | |
| return logRecord; | |
| }; | |
| const logLevelToSeverityNumber = logLevel => { | |
| switch (logLevel) { | |
| case "Trace": | |
| return ESeverityNumber.SEVERITY_NUMBER_TRACE; | |
| case "Debug": | |
| return ESeverityNumber.SEVERITY_NUMBER_DEBUG; | |
| case "Info": | |
| return ESeverityNumber.SEVERITY_NUMBER_INFO; | |
| case "Warn": | |
| return ESeverityNumber.SEVERITY_NUMBER_WARN; | |
| case "Error": | |
| return ESeverityNumber.SEVERITY_NUMBER_ERROR; | |
| case "Fatal": | |
| return ESeverityNumber.SEVERITY_NUMBER_FATAL; | |
| default: | |
| return ESeverityNumber.SEVERITY_NUMBER_UNSPECIFIED; | |
| } | |
| }; | |
| /** | |
| * Numerical value of the severity, normalized to values described in Log Data Model. | |
| */ | |
| const ESeverityNumber = { | |
| /** Unspecified. Do NOT use as default */ | |
| SEVERITY_NUMBER_UNSPECIFIED: 0, | |
| SEVERITY_NUMBER_TRACE: 1, | |
| SEVERITY_NUMBER_TRACE2: 2, | |
| SEVERITY_NUMBER_TRACE3: 3, | |
| SEVERITY_NUMBER_TRACE4: 4, | |
| SEVERITY_NUMBER_DEBUG: 5, | |
| SEVERITY_NUMBER_DEBUG2: 6, | |
| SEVERITY_NUMBER_DEBUG3: 7, | |
| SEVERITY_NUMBER_DEBUG4: 8, | |
| SEVERITY_NUMBER_INFO: 9, | |
| SEVERITY_NUMBER_INFO2: 10, | |
| SEVERITY_NUMBER_INFO3: 11, | |
| SEVERITY_NUMBER_INFO4: 12, | |
| SEVERITY_NUMBER_WARN: 13, | |
| SEVERITY_NUMBER_WARN2: 14, | |
| SEVERITY_NUMBER_WARN3: 15, | |
| SEVERITY_NUMBER_WARN4: 16, | |
| SEVERITY_NUMBER_ERROR: 17, | |
| SEVERITY_NUMBER_ERROR2: 18, | |
| SEVERITY_NUMBER_ERROR3: 19, | |
| SEVERITY_NUMBER_ERROR4: 20, | |
| SEVERITY_NUMBER_FATAL: 21, | |
| SEVERITY_NUMBER_FATAL2: 22, | |
| SEVERITY_NUMBER_FATAL3: 23, | |
| SEVERITY_NUMBER_FATAL4: 24 | |
| }; | |
| //# sourceMappingURL=OtlpLogger.js.map |
Xet Storage Details
- Size:
- 7.24 kB
- Xet hash:
- 97fb772bc51e6e9ddef97cdfc50298b4116fb2e523fcbd4c9d93d3b956be8c9a
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.