From 592001875d178243f47ee8f2d74261e5c85fe261 Mon Sep 17 00:00:00 2001 From: Alessandro Pogliaghi Date: Fri, 6 Feb 2026 07:59:44 +0000 Subject: [PATCH] chore: otel agent logs gated --- apps/twig/src/main/services/agent/service.ts | 42 +++++++++++++++----- packages/agent/src/agent.ts | 20 ++++++---- 2 files changed, 44 insertions(+), 18 deletions(-) diff --git a/apps/twig/src/main/services/agent/service.ts b/apps/twig/src/main/services/agent/service.ts index b084ad2ae..023191547 100644 --- a/apps/twig/src/main/services/agent/service.ts +++ b/apps/twig/src/main/services/agent/service.ts @@ -26,6 +26,7 @@ import { MAIN_TOKENS } from "../../di/tokens.js"; import { logger } from "../../lib/logger.js"; import { TypedEventEmitter } from "../../lib/typed-event-emitter.js"; import type { FsService } from "../fs/service.js"; +import { getCurrentUserId, getPostHogClient } from "../posthog-analytics.js"; import type { ProcessTrackingService } from "../process-tracking/service.js"; import type { SleepService } from "../sleep/service.js"; import { @@ -437,11 +438,16 @@ export class AgentService extends TypedEventEmitter { const mockNodeDir = this.setupMockNodeEnvironment(taskRunId); this.setupEnvironment(credentials, mockNodeDir); - // Route agent logs to dedicated agent_logs Kafka topic via capture-logs-agent service - // In local dev, use Caddy proxy (port 8010) which routes /i/v1/agent-logs to capture-logs-agent - // In prod, use the main API host which proxies /i/v1/agent-logs to capture-logs-agent - const otelHost = credentials.apiHost; - const otelPath = "/i/v1/agent-logs"; + // OTEL log pipeline or legacy S3 writer if FF false + const useOtelPipeline = await this.isFeatureFlagEnabled( + "twig-agent-logs-pipeline", + ); + + log.info("Agent log transport", { + transport: useOtelPipeline ? "otel" : "s3", + taskId, + taskRunId, + }); const agent = new Agent({ posthog: { @@ -449,11 +455,13 @@ export class AgentService extends TypedEventEmitter { getApiKey: () => this.getToken(credentials.apiKey), projectId: credentials.projectId, }, - otelTransport: { - host: otelHost, - apiKey: this.getToken(credentials.apiKey), - logsPath: otelPath, - }, + otelTransport: useOtelPipeline + ? { + host: credentials.apiHost, + apiKey: this.getToken(credentials.apiKey), + logsPath: "/i/v1/agent-logs", + } + : undefined, debug: !app.isPackaged, onLog: onAgentLog, }); @@ -956,6 +964,20 @@ For git operations while detached: return mockNodeDir; } + private async isFeatureFlagEnabled(flagKey: string): Promise { + try { + const client = getPostHogClient(); + const userId = getCurrentUserId(); + if (!client || !userId) { + return false; + } + return (await client.isFeatureEnabled(flagKey, userId)) ?? false; + } catch (error) { + log.warn(`Error checking feature flag "${flagKey}":`, error); + return false; + } + } + private cleanupMockNodeEnvironment(mockNodeDir: string): void { try { rmSync(mockNodeDir, { recursive: true, force: true }); diff --git a/packages/agent/src/agent.ts b/packages/agent/src/agent.ts index 09d79bff4..51be76ffc 100644 --- a/packages/agent/src/agent.ts +++ b/packages/agent/src/agent.ts @@ -32,16 +32,20 @@ export class Agent { this.posthogAPI = new PostHogAPIClient(config.posthog); } - if (config.posthog || config.otelTransport) { + if (config.otelTransport) { + // OTEL pipeline: use OtelLogWriter only (no S3 writer) + this.sessionLogWriter = new SessionLogWriter({ + otelConfig: { + posthogHost: config.otelTransport.host, + apiKey: config.otelTransport.apiKey, + logsPath: config.otelTransport.logsPath, + }, + logger: this.logger.child("SessionLogWriter"), + }); + } else if (config.posthog) { + // Legacy: use S3 writer via PostHog API this.sessionLogWriter = new SessionLogWriter({ posthogAPI: this.posthogAPI, - otelConfig: config.otelTransport - ? { - posthogHost: config.otelTransport.host, - apiKey: config.otelTransport.apiKey, - logsPath: config.otelTransport.logsPath, - } - : undefined, logger: this.logger.child("SessionLogWriter"), }); }