| author | |
| committer | |
| log | fa1e1715538f6f8ac076761f7821f68479f616ab |
| tree | e22554ddb368fcd2d2d12a649fa3662ca59afd86 |
| parent | c14f6015bfe479d313355cb234af1a5c16dbb15f |
| signature | Signed by PGP key B5690EEEBB952194 |
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>12 files changed, 104 insertions(+), 49 deletions(-)
apps/server/src/bin.test.ts+4-3| ... | ... | @@ -15,6 +15,7 @@ import { |
| 15 | 15 | } from "@t3tools/contracts"; |
| 16 | 16 | import * as NetService from "@t3tools/shared/Net"; |
| 17 | 17 | import { HostProcessEnvironment } from "@t3tools/shared/hostProcess"; |
| 18 | import { DEFAULT_SIGNAL_EXPORT } from "@t3tools/shared/observability"; | |
| 18 | 19 | import { assert, it } from "@effect/vitest"; |
| 19 | 20 | import * as Effect from "effect/Effect"; |
| 20 | 21 | import * as DateTime from "effect/DateTime"; |
| ... | ... | @@ -101,10 +102,10 @@ const makeCliTestServerConfig = (baseDir: string) => |
| 101 | 102 | otlpTracesUrl: undefined, |
| 102 | 103 | otlpMetricsUrl: undefined, |
| 103 | 104 | otlpLogsUrl: undefined, |
| 104 | otlpExportIntervalMs: 10_000, | |
| 105 | otlpTracesExport: DEFAULT_SIGNAL_EXPORT, | |
| 106 | otlpMetricsExport: DEFAULT_SIGNAL_EXPORT, | |
| 107 | otlpLogsExport: DEFAULT_SIGNAL_EXPORT, | |
| 105 | 108 | otlpServiceName: "t3-server", |
| 106 | otlpHeaders: undefined, | |
| 107 | otlpProtocol: "http/json", | |
| 108 | 109 | mode: "web", |
| 109 | 110 | port: 0, |
| 110 | 111 | host: "127.0.0.1", |
apps/server/src/cli/config.test.ts+12-7| ... | ... | @@ -17,6 +17,7 @@ import { |
| 17 | 17 | type DesktopBackendBootstrap as DesktopBackendBootstrapValue, |
| 18 | 18 | } from "@t3tools/contracts"; |
| 19 | 19 | import * as NetService from "@t3tools/shared/Net"; |
| 20 | import { DEFAULT_SIGNAL_EXPORT } from "@t3tools/shared/observability"; | |
| 20 | 21 | import * as NodeServices from "@effect/platform-node/NodeServices"; |
| 21 | 22 | import { deriveServerPaths } from "../config.ts"; |
| 22 | 23 | import { resolveServerConfig } from "./config.ts"; |
| ... | ... | @@ -51,10 +52,10 @@ it.layer(NodeServices.layer)("cli config resolution", (it) => { |
| 51 | 52 | otlpTracesUrl: undefined, |
| 52 | 53 | otlpMetricsUrl: undefined, |
| 53 | 54 | otlpLogsUrl: undefined, |
| 54 | otlpExportIntervalMs: 10_000, | |
| 55 | otlpTracesExport: DEFAULT_SIGNAL_EXPORT, | |
| 56 | otlpMetricsExport: DEFAULT_SIGNAL_EXPORT, | |
| 57 | otlpLogsExport: DEFAULT_SIGNAL_EXPORT, | |
| 55 | 58 | otlpServiceName: "t3-server", |
| 56 | otlpHeaders: undefined, | |
| 57 | otlpProtocol: "http/json", | |
| 58 | 59 | devAllowedOrigins: [], |
| 59 | 60 | } as const; |
| 60 | 61 | |
| ... | ... | @@ -764,7 +765,7 @@ it.layer(NodeServices.layer)("cli config resolution", (it) => { |
| 764 | 765 | ), |
| 765 | 766 | ); |
| 766 | 767 | |
| 767 | expect(resolved.otlpHeaders).toEqual({ | |
| 768 | expect(resolved.otlpTracesExport.headers).toEqual({ | |
| 768 | 769 | authorization: "Basic abc==", |
| 769 | 770 | "x-tenant": "t3", |
| 770 | 771 | }); |
| ... | ... | @@ -808,7 +809,7 @@ it.layer(NodeServices.layer)("cli config resolution", (it) => { |
| 808 | 809 | ), |
| 809 | 810 | ); |
| 810 | 811 | |
| 811 | expect(resolved.otlpHeaders).toEqual({ | |
| 812 | expect(resolved.otlpTracesExport.headers).toEqual({ | |
| 812 | 813 | authorization: "Bearer abc==", |
| 813 | 814 | "x-tenant": "t3", |
| 814 | 815 | }); |
| ... | ... | @@ -816,7 +817,7 @@ it.layer(NodeServices.layer)("cli config resolution", (it) => { |
| 816 | 817 | }), |
| 817 | 818 | ); |
| 818 | 819 | |
| 819 | it.effect("reads the OTLP protocol from env", () => | |
| 820 | it.effect("gives every signal the protocol named without one", () => | |
| 820 | 821 | Effect.gen(function* () { |
| 821 | 822 | const { join } = yield* Path.Path; |
| 822 | 823 | const baseDir = join(NodeOS.tmpdir(), "t3-cli-config-otlp-protocol-base"); |
| ... | ... | @@ -848,7 +849,11 @@ it.layer(NodeServices.layer)("cli config resolution", (it) => { |
| 848 | 849 | ), |
| 849 | 850 | ); |
| 850 | 851 | |
| 851 | expect(resolved.otlpProtocol).toBe("http/protobuf"); | |
| 852 | expect([ | |
| 853 | resolved.otlpTracesExport.protocol, | |
| 854 | resolved.otlpMetricsExport.protocol, | |
| 855 | resolved.otlpLogsExport.protocol, | |
| 856 | ]).toEqual(["http/protobuf", "http/protobuf", "http/protobuf"]); | |
| 852 | 857 | }), |
| 853 | 858 | ); |
| 854 | 859 |
apps/server/src/cli/config.ts+16-4| ... | ... | @@ -1,5 +1,9 @@ |
| 1 | 1 | import * as NetService from "@t3tools/shared/Net"; |
| 2 | import { OtlpHeadersFromString, OtlpProtocol } from "@t3tools/shared/observability"; | |
| 2 | import { | |
| 3 | OtlpHeadersFromString, | |
| 4 | OtlpProtocol, | |
| 5 | type SignalExport, | |
| 6 | } from "@t3tools/shared/observability"; | |
| 3 | 7 | import { parsePersistedServerObservabilitySettings } from "@t3tools/shared/serverSettings"; |
| 4 | 8 | import { DesktopBackendBootstrap, PortSchema } from "@t3tools/contracts"; |
| 5 | 9 | import * as Config from "effect/Config"; |
| ... | ... | @@ -382,6 +386,14 @@ export const resolveServerConfig = ( |
| 382 | 386 | ); |
| 383 | 387 | const logLevel = Option.getOrElse(cliLogLevel, () => env.logLevel); |
| 384 | 388 | |
| 389 | // T3 Code's own OTLP variables name no signal, so the one answer they give | |
| 390 | // is the answer for all three. | |
| 391 | const signalExport: SignalExport = { | |
| 392 | protocol: env.otlpProtocol, | |
| 393 | headers: env.otlpHeaders, | |
| 394 | exportIntervalMs: env.otlpExportIntervalMs, | |
| 395 | }; | |
| 396 | ||
| 385 | 397 | const config: ServerConfig.ServerConfig["Service"] = { |
| 386 | 398 | logLevel, |
| 387 | 399 | traceMinLevel: env.traceMinLevel, |
| ... | ... | @@ -399,10 +411,10 @@ export const resolveServerConfig = ( |
| 399 | 411 | persistedObservabilitySettings.otlpMetricsUrl, |
| 400 | 412 | otlpLogsUrl: |
| 401 | 413 | env.otlpLogsUrl ?? bootstrap?.otlpLogsUrl ?? persistedObservabilitySettings.otlpLogsUrl, |
| 402 | otlpExportIntervalMs: env.otlpExportIntervalMs, | |
| 414 | otlpTracesExport: signalExport, | |
| 415 | otlpMetricsExport: signalExport, | |
| 416 | otlpLogsExport: signalExport, | |
| 403 | 417 | otlpServiceName: env.otlpServiceName, |
| 404 | otlpHeaders: env.otlpHeaders, | |
| 405 | otlpProtocol: env.otlpProtocol, | |
| 406 | 418 | mode, |
| 407 | 419 | port, |
| 408 | 420 | cwd, |
apps/server/src/cli/pair.ts+4-3| ... | ... | @@ -15,6 +15,7 @@ import { |
| 15 | 15 | PortSchema, |
| 16 | 16 | } from "@t3tools/contracts"; |
| 17 | 17 | import { resolveWorktreeT3Home } from "@t3tools/shared/devHome"; |
| 18 | import { DEFAULT_SIGNAL_EXPORT } from "@t3tools/shared/observability"; | |
| 18 | 19 | import { |
| 19 | 20 | buildTailscaleHttpsBaseUrl, |
| 20 | 21 | DEFAULT_TAILSCALE_SERVE_PORT, |
| ... | ... | @@ -321,10 +322,10 @@ const makePairServerConfig = Effect.fn(function* (input: { |
| 321 | 322 | otlpTracesUrl: undefined, |
| 322 | 323 | otlpMetricsUrl: undefined, |
| 323 | 324 | otlpLogsUrl: undefined, |
| 324 | otlpExportIntervalMs: 10_000, | |
| 325 | otlpTracesExport: DEFAULT_SIGNAL_EXPORT, | |
| 326 | otlpMetricsExport: DEFAULT_SIGNAL_EXPORT, | |
| 327 | otlpLogsExport: DEFAULT_SIGNAL_EXPORT, | |
| 325 | 328 | otlpServiceName: "t3-server", |
| 326 | otlpHeaders: undefined, | |
| 327 | otlpProtocol: "http/json", | |
| 328 | 329 | mode: "web", |
| 329 | 330 | port: state.port, |
| 330 | 331 | host: state.host, |
apps/server/src/config.ts+12-7| ... | ... | @@ -17,7 +17,7 @@ import type * as Redacted from "effect/Redacted"; |
| 17 | 17 | import * as Schema from "effect/Schema"; |
| 18 | 18 | |
| 19 | 19 | import { sweepStalePendingAttachments } from "./attachmentStore.ts"; |
| 20 | import { OtlpProtocol } from "@t3tools/shared/observability"; | |
| 20 | import { DEFAULT_SIGNAL_EXPORT, type SignalExport } from "@t3tools/shared/observability"; | |
| 21 | 21 | |
| 22 | 22 | export const DEFAULT_PORT = 3773; |
| 23 | 23 | |
| ... | ... | @@ -73,10 +73,15 @@ export class ServerConfig extends Context.Service< |
| 73 | 73 | readonly otlpTracesUrl: string | undefined; |
| 74 | 74 | readonly otlpMetricsUrl: string | undefined; |
| 75 | 75 | readonly otlpLogsUrl: string | undefined; |
| 76 | readonly otlpExportIntervalMs: number; | |
| 76 | /** | |
| 77 | * How each signal is exported. Read instead of a process-wide setting so | |
| 78 | * the wire format, credential, and schedule travel with the endpoint they | |
| 79 | * were configured beside. | |
| 80 | */ | |
| 81 | readonly otlpTracesExport: SignalExport; | |
| 82 | readonly otlpMetricsExport: SignalExport; | |
| 83 | readonly otlpLogsExport: SignalExport; | |
| 77 | 84 | readonly otlpServiceName: string; |
| 78 | readonly otlpHeaders: Readonly<Record<string, string>> | undefined; | |
| 79 | readonly otlpProtocol: OtlpProtocol; | |
| 80 | 85 | readonly mode: RuntimeMode; |
| 81 | 86 | readonly port: number; |
| 82 | 87 | readonly host: string | undefined; |
| ... | ... | @@ -212,10 +217,10 @@ const makeTest = Effect.fn("ServerConfig.makeTest")(function* ( |
| 212 | 217 | otlpTracesUrl: undefined, |
| 213 | 218 | otlpMetricsUrl: undefined, |
| 214 | 219 | otlpLogsUrl: undefined, |
| 215 | otlpExportIntervalMs: 10_000, | |
| 220 | otlpTracesExport: DEFAULT_SIGNAL_EXPORT, | |
| 221 | otlpMetricsExport: DEFAULT_SIGNAL_EXPORT, | |
| 222 | otlpLogsExport: DEFAULT_SIGNAL_EXPORT, | |
| 216 | 223 | otlpServiceName: "t3-server", |
| 217 | otlpHeaders: undefined, | |
| 218 | otlpProtocol: "http/json", | |
| 219 | 224 | cwd, |
| 220 | 225 | baseDir, |
| 221 | 226 | ...derivedPaths, |
apps/server/src/environment/ServerEnvironment.test.ts+5-3| ... | ... | @@ -10,6 +10,8 @@ import * as Option from "effect/Option"; |
| 10 | 10 | import * as PlatformError from "effect/PlatformError"; |
| 11 | 11 | import * as Schema from "effect/Schema"; |
| 12 | 12 | |
| 13 | import { DEFAULT_SIGNAL_EXPORT } from "@t3tools/shared/observability"; | |
| 14 | ||
| 13 | 15 | import * as ServerSecretStore from "../auth/ServerSecretStore.ts"; |
| 14 | 16 | import { |
| 15 | 17 | PUBLISH_AGENT_ACTIVITY_SECRET, |
| ... | ... | @@ -54,10 +56,10 @@ const makeServerConfig = Effect.fn(function* (baseDir: string) { |
| 54 | 56 | otlpTracesUrl: undefined, |
| 55 | 57 | otlpMetricsUrl: undefined, |
| 56 | 58 | otlpLogsUrl: undefined, |
| 57 | otlpExportIntervalMs: 10_000, | |
| 59 | otlpTracesExport: DEFAULT_SIGNAL_EXPORT, | |
| 60 | otlpMetricsExport: DEFAULT_SIGNAL_EXPORT, | |
| 61 | otlpLogsExport: DEFAULT_SIGNAL_EXPORT, | |
| 58 | 62 | otlpServiceName: "t3-server", |
| 59 | otlpHeaders: undefined, | |
| 60 | otlpProtocol: "http/json", | |
| 61 | 63 | cwd: process.cwd(), |
| 62 | 64 | baseDir, |
| 63 | 65 | mode: "web", |
apps/server/src/http.ts+1-1| ... | ... | @@ -322,7 +322,7 @@ export const otlpTracesProxyRouteLayer = HttpRouter.add( |
| 322 | 322 | const request = yield* HttpServerRequest.HttpServerRequest; |
| 323 | 323 | const config = yield* ServerConfig.ServerConfig; |
| 324 | 324 | const otlpTracesUrl = config.otlpTracesUrl; |
| 325 | const otlpHeaders = config.otlpHeaders; | |
| 325 | const otlpHeaders = config.otlpTracesExport.headers; | |
| 326 | 326 | const browserTraceCollector = yield* BrowserTraceCollector.BrowserTraceCollector; |
| 327 | 327 | const httpClient = yield* HttpClient.HttpClient; |
| 328 | 328 | const serialization = yield* OtlpSerialization.OtlpSerialization; |
apps/server/src/observability/Layers/Observability.ts+10-6| ... | ... | @@ -20,7 +20,11 @@ import * as BrowserTraceCollector from "../BrowserTraceCollector.ts"; |
| 20 | 20 | export const ObservabilityLive = Layer.unwrap( |
| 21 | 21 | Effect.gen(function* () { |
| 22 | 22 | const config = yield* ServerConfig.ServerConfig; |
| 23 | const serializationLayer = otlpSerializationLayer(config.otlpProtocol); | |
| 23 | const traces = config.otlpTracesExport; | |
| 24 | const metrics = config.otlpMetricsExport; | |
| 25 | // The trace serializer stays in the returned context because the browser | |
| 26 | // trace forwarder exports on the same signal. | |
| 27 | const serializationLayer = otlpSerializationLayer(traces.protocol); | |
| 24 | 28 | const resource = ServerConfig.otlpResource(config); |
| 25 | 29 | const attribution = yield* ResourceAttribution.ResourceAttribution; |
| 26 | 30 | |
| ... | ... | @@ -51,8 +55,8 @@ export const ObservabilityLive = Layer.unwrap( |
| 51 | 55 | ? undefined |
| 52 | 56 | : yield* OtlpTracer.make({ |
| 53 | 57 | url: config.otlpTracesUrl, |
| 54 | exportInterval: `${config.otlpExportIntervalMs} millis`, | |
| 55 | headers: config.otlpHeaders, | |
| 58 | exportInterval: `${traces.exportIntervalMs} millis`, | |
| 59 | headers: traces.headers, | |
| 56 | 60 | resource, |
| 57 | 61 | }); |
| 58 | 62 | |
| ... | ... | @@ -77,10 +81,10 @@ export const ObservabilityLive = Layer.unwrap( |
| 77 | 81 | ? Layer.empty |
| 78 | 82 | : OtlpMetrics.layer({ |
| 79 | 83 | url: config.otlpMetricsUrl, |
| 80 | exportInterval: `${config.otlpExportIntervalMs} millis`, | |
| 81 | headers: config.otlpHeaders, | |
| 84 | exportInterval: `${metrics.exportIntervalMs} millis`, | |
| 85 | headers: metrics.headers, | |
| 82 | 86 | resource, |
| 83 | }).pipe(Layer.provideMerge(serializationLayer)); | |
| 87 | }).pipe(Layer.provide(otlpSerializationLayer(metrics.protocol))); | |
| 84 | 88 | |
| 85 | 89 | return Layer.mergeAll(ServerLoggerLive, traceReferencesLayer, tracerLayer, metricsLayer); |
| 86 | 90 | }), |
apps/server/src/server.test.ts+6-6| ... | ... | @@ -218,7 +218,7 @@ import { |
| 218 | 218 | transferBudgetViolations, |
| 219 | 219 | } from "../integration/TransferBudgetReport.integration.ts"; |
| 220 | 220 | import { symlinksSupported } from "@t3tools/shared/testing/symlinks"; |
| 221 | import { otlpSerializationLayer } from "@t3tools/shared/observability"; | |
| 221 | import { DEFAULT_SIGNAL_EXPORT, otlpSerializationLayer } from "@t3tools/shared/observability"; | |
| 222 | 222 | |
| 223 | 223 | const defaultProjectId = ProjectId.make("project-default"); |
| 224 | 224 | const defaultThreadId = ThreadId.make("thread-default"); |
| ... | ... | @@ -578,10 +578,10 @@ const buildAppUnderTest = (options?: { |
| 578 | 578 | otlpTracesUrl: undefined, |
| 579 | 579 | otlpMetricsUrl: undefined, |
| 580 | 580 | otlpLogsUrl: undefined, |
| 581 | otlpExportIntervalMs: 10_000, | |
| 581 | otlpTracesExport: DEFAULT_SIGNAL_EXPORT, | |
| 582 | otlpMetricsExport: DEFAULT_SIGNAL_EXPORT, | |
| 583 | otlpLogsExport: DEFAULT_SIGNAL_EXPORT, | |
| 582 | 584 | otlpServiceName: "t3-server", |
| 583 | otlpHeaders: undefined, | |
| 584 | otlpProtocol: "http/json", | |
| 585 | 585 | mode: "desktop", |
| 586 | 586 | port: 0, |
| 587 | 587 | host: "127.0.0.1", |
| ... | ... | @@ -1076,7 +1076,7 @@ const buildAppUnderTest = (options?: { |
| 1076 | 1076 | ...options?.layers?.browserTraceCollector, |
| 1077 | 1077 | }), |
| 1078 | 1078 | ), |
| 1079 | Layer.provide(otlpSerializationLayer(config.otlpProtocol)), | |
| 1079 | Layer.provide(otlpSerializationLayer(config.otlpTracesExport.protocol)), | |
| 1080 | 1080 | Layer.provide( |
| 1081 | 1081 | Layer.mock(ServerLifecycleEvents.ServerLifecycleEvents)({ |
| 1082 | 1082 | publish: (event) => Effect.succeed({ ...(event as any), sequence: 1 }), |
| ... | ... | @@ -5299,7 +5299,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { |
| 5299 | 5299 | yield* buildAppUnderTest({ |
| 5300 | 5300 | config: { |
| 5301 | 5301 | otlpTracesUrl: collector.url, |
| 5302 | otlpProtocol: "http/protobuf", | |
| 5302 | otlpTracesExport: { ...DEFAULT_SIGNAL_EXPORT, protocol: "http/protobuf" }, | |
| 5303 | 5303 | }, |
| 5304 | 5304 | layers: { |
| 5305 | 5305 | browserTraceCollector: { |
apps/server/src/serverLogger.test.ts+11-6| ... | ... | @@ -8,6 +8,8 @@ import * as Tracer from "effect/Tracer"; |
| 8 | 8 | import * as HttpClient from "effect/unstable/http/HttpClient"; |
| 9 | 9 | import * as HttpClientResponse from "effect/unstable/http/HttpClientResponse"; |
| 10 | 10 | |
| 11 | import { DEFAULT_SIGNAL_EXPORT } from "@t3tools/shared/observability"; | |
| 12 | ||
| 11 | 13 | import * as ServerConfig from "./config.ts"; |
| 12 | 14 | import { ServerLoggerLive } from "./serverLogger.ts"; |
| 13 | 15 | |
| ... | ... | @@ -51,10 +53,10 @@ const configLayer = (overrides: Partial<ServerConfig.ServerConfig["Service"]>) = |
| 51 | 53 | otlpTracesUrl: undefined, |
| 52 | 54 | otlpMetricsUrl: undefined, |
| 53 | 55 | otlpLogsUrl: undefined, |
| 54 | otlpExportIntervalMs: 10_000, | |
| 56 | otlpTracesExport: DEFAULT_SIGNAL_EXPORT, | |
| 57 | otlpMetricsExport: DEFAULT_SIGNAL_EXPORT, | |
| 58 | otlpLogsExport: DEFAULT_SIGNAL_EXPORT, | |
| 55 | 59 | otlpServiceName: "t3-server", |
| 56 | otlpHeaders: undefined, | |
| 57 | otlpProtocol: "http/json", | |
| 58 | 60 | cwd: baseDir, |
| 59 | 61 | baseDir, |
| 60 | 62 | ...derivedPaths, |
| ... | ... | @@ -155,12 +157,15 @@ describe("ServerLoggerLive", () => { |
| 155 | 157 | }), |
| 156 | 158 | ); |
| 157 | 159 | |
| 158 | it.effect("sends the headers and wire format the rest of OTLP export already uses", () => | |
| 160 | it.effect("sends the headers and wire format the log signal asked for", () => | |
| 159 | 161 | Effect.gen(function* () { |
| 160 | 162 | const requests = yield* logThrough({ |
| 161 | 163 | otlpLogsUrl: "https://collector.example.com/v1/logs", |
| 162 | otlpProtocol: "http/protobuf", | |
| 163 | otlpHeaders: { "x-scope": "logs" }, | |
| 164 | otlpLogsExport: { | |
| 165 | ...DEFAULT_SIGNAL_EXPORT, | |
| 166 | protocol: "http/protobuf", | |
| 167 | headers: { "x-scope": "logs" }, | |
| 168 | }, | |
| 164 | 169 | }); |
| 165 | 170 | |
| 166 | 171 | assert.lengthOf(requests, 1); |
apps/server/src/serverLogger.ts+4-3| ... | ... | @@ -12,13 +12,14 @@ export const ServerLoggerLive = Effect.gen(function* () { |
| 12 | 12 | const config = yield* ServerConfig; |
| 13 | 13 | const minimumLogLevelLayer = Layer.succeed(References.MinimumLogLevel, config.logLevel); |
| 14 | 14 | |
| 15 | const logs = config.otlpLogsExport; | |
| 15 | 16 | const otlpLogger = |
| 16 | 17 | config.otlpLogsUrl === undefined |
| 17 | 18 | ? undefined |
| 18 | 19 | : OtlpLogger.make({ |
| 19 | 20 | url: config.otlpLogsUrl, |
| 20 | exportInterval: `${config.otlpExportIntervalMs} millis`, | |
| 21 | headers: config.otlpHeaders, | |
| 21 | exportInterval: `${logs.exportIntervalMs} millis`, | |
| 22 | headers: logs.headers, | |
| 22 | 23 | resource: otlpResource(config), |
| 23 | 24 | }); |
| 24 | 25 | |
| ... | ... | @@ -41,7 +42,7 @@ export const ServerLoggerLive = Effect.gen(function* () { |
| 41 | 42 | { mergeWithExisting: false }, |
| 42 | 43 | ).pipe( |
| 43 | 44 | Layer.provide(OtlpExporter.layerFlusher), |
| 44 | Layer.provide(otlpSerializationLayer(config.otlpProtocol)), | |
| 45 | Layer.provide(otlpSerializationLayer(logs.protocol)), | |
| 45 | 46 | ); |
| 46 | 47 | |
| 47 | 48 | return Layer.mergeAll(loggerLayer, minimumLogLevelLayer); |
packages/shared/src/observability.ts+19| ... | ... | @@ -16,6 +16,25 @@ export type OtlpProtocol = typeof OtlpProtocol.Type; |
| 16 | 16 | export const otlpSerializationLayer = (protocol: OtlpProtocol) => |
| 17 | 17 | protocol === "http/protobuf" ? OtlpSerialization.layerProtobuf : OtlpSerialization.layerJson; |
| 18 | 18 | |
| 19 | /** | |
| 20 | * How one signal is exported, once whichever source named that signal's | |
| 21 | * endpoint has been resolved. Held per signal rather than per process, so a | |
| 22 | * wire format or a credential cannot be paired by hand with an endpoint that | |
| 23 | * came from somewhere else. | |
| 24 | */ | |
| 25 | export interface SignalExport { | |
| 26 | readonly protocol: OtlpProtocol; | |
| 27 | readonly headers: Readonly<Record<string, string>> | undefined; | |
| 28 | readonly exportIntervalMs: number; | |
| 29 | } | |
| 30 | ||
| 31 | /** What T3 Code exports with when nothing configured a signal. */ | |
| 32 | export const DEFAULT_SIGNAL_EXPORT: SignalExport = { | |
| 33 | protocol: "http/json", | |
| 34 | headers: undefined, | |
| 35 | exportIntervalMs: 10_000, | |
| 36 | }; | |
| 37 | ||
| 19 | 38 | const FLUSH_BUFFER_THRESHOLD = 256; |
| 20 | 39 | const textEncoder = new TextEncoder(); |
| 21 | 40 |