From 94b1fafd96e2cd3c0b45c91a1ddd46182fd13c07 Mon Sep 17 00:00:00 2001 From: Neal Shah Date: Mon, 13 Jul 2026 02:08:26 -0400 Subject: [PATCH] move install location --- src/backend/index.ts | 19 ++++++++++++++ src/backend/telemetry.ts | 54 ---------------------------------------- 2 files changed, 19 insertions(+), 54 deletions(-) diff --git a/src/backend/index.ts b/src/backend/index.ts index 9d5f66519..b2a8d55cf 100644 --- a/src/backend/index.ts +++ b/src/backend/index.ts @@ -19,6 +19,7 @@ import { existsSync, readFileSync } from 'node:fs'; import path from 'node:path'; +import { isSpanContextValid, trace } from '@opentelemetry/api'; import { puterClients } from './clients'; import { puterControllers } from './controllers'; import { puterDrivers } from './drivers'; @@ -26,6 +27,7 @@ import { PuterServer } from './server'; import { puterServices } from './services'; import { puterStores } from './stores'; import type { IConfig } from './types'; +import { installJsonConsole } from './util/jsonConsole.js'; // Config resolution order: // 1. `process.env.PUTER_CONFIG_PATH` — absolute path to a config file. Used @@ -167,6 +169,23 @@ const loadConfig = (): IConfig => { // if called directly, start the server if (require.main === module) { const config = loadConfig(); + + // Structured logging: when `log_format: "json"`, replace the global console + // so each call emits one JSON line (level, timestamp, msg, and the active + // trace id) — one event per call, so a line-oriented log collector can't + // split stack traces across events. Installed here rather than in the OTel + // preload so it applies even when telemetry is disabled; the trace id is + // simply absent when no span is active. + if (config.log_format === 'json') { + installJsonConsole({ + getTraceContext: () => { + const ctx = trace.getActiveSpan()?.spanContext(); + if (!ctx || !isSpanContextValid(ctx)) return undefined; + return { traceId: ctx.traceId, spanId: ctx.spanId }; + }, + }); + } + const server = new PuterServer( config, puterClients, diff --git a/src/backend/telemetry.ts b/src/backend/telemetry.ts index 3b15c8ce1..d8aed4257 100644 --- a/src/backend/telemetry.ts +++ b/src/backend/telemetry.ts @@ -17,7 +17,6 @@ * along with this program. If not, see . */ -import { isSpanContextValid, trace } from '@opentelemetry/api'; import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'; import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-grpc'; import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc'; @@ -33,59 +32,6 @@ import { ATTR_SERVICE_VERSION, } from '@opentelemetry/semantic-conventions'; -import { existsSync, readFileSync } from 'node:fs'; -import path from 'node:path'; -import { installJsonConsole } from './util/jsonConsole.js'; - -/** - * Resolve `log_format` with the SAME precedence as the server's `loadConfig` - * (index.ts): defaults from `config.default.json`, overlaid by a single - * override file — `PUTER_CONFIG_PATH` if it exists, else `/config.json`. - * This preload runs before the backend loads config, so it must stay in lockstep - * with that resolution or it'd act on a value the server never sees. - */ -const configLogFormat = (): unknown => { - const pkgRoot = path.resolve(__dirname, '../../..'); - const readJson = (file: string): Record => { - try { - return JSON.parse(readFileSync(file, 'utf8')); - } catch { - // A missing/invalid file is treated as no override; the server's - // loadConfig surfaces a real parse error moments later. - return {}; - } - }; - - const defaultPath = path.join(pkgRoot, 'config.default.json'); - const runtimePath = path.join(pkgRoot, 'config.json'); - const envPath = process.env.PUTER_CONFIG_PATH; - - const defaults = existsSync(defaultPath) ? readJson(defaultPath) : {}; - const overridePath = - envPath && existsSync(envPath) - ? envPath - : existsSync(runtimePath) - ? runtimePath - : null; - const override = overridePath ? readJson(overridePath) : {}; - - // deepMerge over a scalar key == override wins when it sets the key. - return 'log_format' in override ? override.log_format : defaults.log_format; -}; - -// When config sets `log_format: "json"`, replace the global console so every -// call emits one JSON line tagged with the active trace — one event per call, -// filterable by level. Any other value (the default) leaves console untouched. -if (configLogFormat() === 'json') { - installJsonConsole({ - getTraceContext: () => { - const ctx = trace.getActiveSpan()?.spanContext(); - if (!ctx || !isSpanContextValid(ctx)) return undefined; - return { traceId: ctx.traceId, spanId: ctx.spanId }; - }, - }); -} - const endpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT ?? 'http://localhost:4317'; const sampleRatio = Number(process.env.OTEL_TRACE_SAMPLE_RATIO ?? 0.05);