Skip to content

Commit aa4500b

Browse files
committed
fix(component-sdk): gate component diagnostic logs
Signed-off-by: zebbern <185730623+zebbern@users.noreply.github.com>
1 parent 79a7425 commit aa4500b

2 files changed

Lines changed: 128 additions & 21 deletions

File tree

packages/component-sdk/src/__tests__/context.test.ts

Lines changed: 81 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { describe, it, expect } from 'bun:test';
1+
import { describe, it, expect, vi } from 'bun:test';
22
import { createExecutionContext } from '../context';
33
import type { IFileStorageService, ISecretsService, TraceEvent } from '../interfaces';
44

@@ -34,7 +34,6 @@ describe('ExecutionContext', () => {
3434
uploadFile: async () => {},
3535
};
3636

37-
3837
const context = createExecutionContext({
3938
runId: 'test-run',
4039
componentRef: 'test.component',
@@ -91,6 +90,86 @@ describe('ExecutionContext', () => {
9190
expect(recordedEvents[1].level).toBe('info');
9291
});
9392

93+
it('does not mirror progress events to console.log by default', () => {
94+
const previousDebugFlag = process.env.SENTRIS_DEBUG_COMPONENTS;
95+
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
96+
97+
try {
98+
delete process.env.SENTRIS_DEBUG_COMPONENTS;
99+
100+
const recordedEvents: TraceEvent[] = [];
101+
const context = createExecutionContext({
102+
runId: 'run-quiet-progress',
103+
componentRef: 'quiet.progress',
104+
trace: {
105+
record: (event: TraceEvent) => {
106+
recordedEvents.push(event);
107+
},
108+
},
109+
});
110+
111+
context.emitProgress('Processing quietly');
112+
113+
expect(recordedEvents).toHaveLength(1);
114+
expect(recordedEvents[0]).toMatchObject({
115+
type: 'NODE_PROGRESS',
116+
message: 'Processing quietly',
117+
});
118+
expect(logSpy).not.toHaveBeenCalled();
119+
} finally {
120+
if (previousDebugFlag === undefined) {
121+
delete process.env.SENTRIS_DEBUG_COMPONENTS;
122+
} else {
123+
process.env.SENTRIS_DEBUG_COMPONENTS = previousDebugFlag;
124+
}
125+
logSpy.mockRestore();
126+
}
127+
});
128+
129+
it('does not mirror info and debug logger output to console by default', () => {
130+
const previousDebugFlag = process.env.SENTRIS_DEBUG_COMPONENTS;
131+
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
132+
const debugSpy = vi.spyOn(console, 'debug').mockImplementation(() => {});
133+
134+
try {
135+
delete process.env.SENTRIS_DEBUG_COMPONENTS;
136+
137+
const logEntries: Array<{
138+
level?: string;
139+
message: string;
140+
}> = [];
141+
142+
const context = createExecutionContext({
143+
runId: 'run-quiet-logger',
144+
componentRef: 'quiet.logger',
145+
logCollector: (entry) => {
146+
logEntries.push({
147+
level: entry.level,
148+
message: entry.message,
149+
});
150+
},
151+
});
152+
153+
context.logger.info('hello world');
154+
context.logger.debug('debug detail');
155+
156+
expect(logEntries).toEqual([
157+
{ level: 'info', message: 'hello world' },
158+
{ level: 'debug', message: 'debug detail' },
159+
]);
160+
expect(logSpy).not.toHaveBeenCalled();
161+
expect(debugSpy).not.toHaveBeenCalled();
162+
} finally {
163+
if (previousDebugFlag === undefined) {
164+
delete process.env.SENTRIS_DEBUG_COMPONENTS;
165+
} else {
166+
process.env.SENTRIS_DEBUG_COMPONENTS = previousDebugFlag;
167+
}
168+
logSpy.mockRestore();
169+
debugSpy.mockRestore();
170+
}
171+
});
172+
94173
it('should support structured progress payloads', () => {
95174
const recordedEvents: TraceEvent[] = [];
96175
const mockTrace = {

packages/component-sdk/src/context.ts

Lines changed: 47 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,23 @@
11
// Simple format function to avoid webpack issues with node:util
22
function format(...args: unknown[]): string {
3-
return args.map(arg => {
4-
if (typeof arg === 'string') return arg;
5-
if (arg === null || arg === undefined) return String(arg);
6-
if (typeof arg === 'object') {
7-
try {
8-
return JSON.stringify(arg);
9-
} catch {
10-
return String(arg);
3+
return args
4+
.map((arg) => {
5+
if (typeof arg === 'string') return arg;
6+
if (arg === null || arg === undefined) return String(arg);
7+
if (typeof arg === 'object') {
8+
try {
9+
return JSON.stringify(arg);
10+
} catch {
11+
return String(arg);
12+
}
1113
}
12-
}
13-
return String(arg);
14-
}).join(' ');
14+
return String(arg);
15+
})
16+
.join(' ');
17+
}
18+
19+
function shouldMirrorComponentDiagnostics(): boolean {
20+
return process.env.SENTRIS_DEBUG_COMPONENTS === '1';
1521
}
1622

1723
import type {
@@ -51,8 +57,21 @@ export interface CreateContextOptions {
5157
}
5258

5359
export function createExecutionContext(options: CreateContextOptions): ExecutionContext {
54-
const { runId, componentRef, metadata: metadataInput, storage, secrets, artifacts, trace, logCollector, terminalCollector, agentTracePublisher, workflowId, workflowName, organizationId } =
55-
options;
60+
const {
61+
runId,
62+
componentRef,
63+
metadata: metadataInput,
64+
storage,
65+
secrets,
66+
artifacts,
67+
trace,
68+
logCollector,
69+
terminalCollector,
70+
agentTracePublisher,
71+
workflowId,
72+
workflowName,
73+
organizationId,
74+
} = options;
5675
const metadata = createMetadata(runId, componentRef, metadataInput);
5776
const scopedTrace = trace ? createScopedTrace(trace, metadata) : undefined;
5877

@@ -98,11 +117,15 @@ export function createExecutionContext(options: CreateContextOptions): Execution
98117
const logger: Logger = Object.freeze({
99118
debug: (...args: unknown[]) => {
100119
pushLog('stdout', 'debug', args);
101-
console.debug(`[${componentRef}]`, ...args);
120+
if (shouldMirrorComponentDiagnostics()) {
121+
console.debug(`[${componentRef}]`, ...args);
122+
}
102123
},
103124
info: (...args: unknown[]) => {
104125
pushLog('stdout', 'info', args);
105-
console.log(`[${componentRef}]`, ...args);
126+
if (shouldMirrorComponentDiagnostics()) {
127+
console.log(`[${componentRef}]`, ...args);
128+
}
106129
},
107130
warn: (...args: unknown[]) => {
108131
pushLog('stdout', 'warn', args);
@@ -114,14 +137,15 @@ export function createExecutionContext(options: CreateContextOptions): Execution
114137
},
115138
}) as Logger;
116139

117-
118140
const emitProgress = (progress: ProgressEventInput | string) => {
119141
const normalized: ProgressEventInput =
120142
typeof progress === 'string' ? { message: progress, level: 'info' } : progress;
121143
const level = normalized.level ?? 'info';
122144
const message = normalized.message;
123145

124-
console.log(`[${componentRef}] progress [${level}]: ${message}`);
146+
if (shouldMirrorComponentDiagnostics()) {
147+
console.log(`[${componentRef}] progress [${level}]: ${message}`);
148+
}
125149
if (scopedTrace) {
126150
scopedTrace.record({
127151
type: 'NODE_PROGRESS',
@@ -169,7 +193,9 @@ export function createExecutionContext(options: CreateContextOptions): Execution
169193
timestamp: new Date().toISOString(),
170194
metadata,
171195
});
172-
console.debug(`[${componentRef}]`, ...args);
196+
if (shouldMirrorComponentDiagnostics()) {
197+
console.debug(`[${componentRef}]`, ...args);
198+
}
173199
},
174200
info: (...args: unknown[]) => {
175201
logCollector({
@@ -181,7 +207,9 @@ export function createExecutionContext(options: CreateContextOptions): Execution
181207
timestamp: new Date().toISOString(),
182208
metadata,
183209
});
184-
console.log(`[${componentRef}]`, ...args);
210+
if (shouldMirrorComponentDiagnostics()) {
211+
console.log(`[${componentRef}]`, ...args);
212+
}
185213
},
186214
warn: (...args: unknown[]) => {
187215
logCollector({

0 commit comments

Comments
 (0)