forked from zereight/gitlab-mcp
-
Notifications
You must be signed in to change notification settings - Fork 1
fix(logging): Apply LOG_JSON pattern to all logger calls (multiline output remains in 144 places) #209
Copy link
Copy link
Closed
Labels
Description
Problem
Issue #207 fixed multiline output for access logs only, but the same problem persists in 144 other places across the codebase.
Evidence from production logs (gm.sw.foundation)
Jan 25 14:25:37 gitlab-mcp.sw.foundation node[39293]: [14:25:37.597] INFO (gitlab-mcp): OAuth mode: unauthenticated version detection failed, deferring all introspection
Jan 25 14:25:37 gitlab-mcp.sw.foundation node[39293]: status: 401
The status: 401 appears on a separate line because of:
// src/services/ConnectionManager.ts:108-111
logger.info(
{ status: versionResponse.status },
"OAuth mode: unauthenticated version detection failed, deferring all introspection"
);Scope of the Problem
$ grep -rE 'logger\.(info|warn|error|debug)\(\s*\{' src/ | wc -l
144144 occurrences across 28 files use logger.level({ object }, "message") pattern which causes multiline output in plain text mode.
Files Affected
| File | Count |
|---|---|
src/oauth/session-store.ts |
20 |
src/server.ts |
15 |
src/oauth/storage/memory.ts |
11 |
src/discovery/auto.ts |
10 |
src/main.ts |
8 |
src/entities/context/context-manager.ts |
7 |
src/profiles/loader.ts |
7 |
src/profiles/project-loader.ts |
7 |
src/session-manager.ts |
7 |
src/oauth/gitlab-device-flow.ts |
7 |
| ... 18 more files | ... |
Root Cause
Issue #207 introduced the LOG_JSON pattern for access logs:
// src/logging/request-tracker.ts (fixed in #207)
if (LOG_JSON) {
logger.info({ accessLog: entry }, logLine);
} else {
logger.info(logLine); // No object = no multiline
}But this pattern was only applied to access logs, not to the 144 other logger calls.
Solution
Apply the same pattern from #207 to all logger calls:
Option A: Global Helper Function (Recommended)
Create a helper that handles both modes transparently:
// src/logger.ts
export function logInfo(message: string, data?: Record<string, unknown>): void {
if (LOG_JSON) {
logger.info(data ?? {}, message);
} else if (data && Object.keys(data).length > 0) {
const pairs = Object.entries(data)
.map(([k, v]) => `${k}=${typeof v === 'object' ? JSON.stringify(v) : v}`)
.join(' ');
logger.info(`${message} ${pairs}`);
} else {
logger.info(message);
}
}
// Similar helpers: logWarn, logError, logDebugThen update all calls:
// Before
logger.info({ status: 401 }, "Version detection failed");
// After
logInfo("Version detection failed", { status: 401 });Option B: Conditional Logging at Each Call Site
Use LOG_JSON check at each location (more verbose but explicit):
if (LOG_JSON) {
logger.info({ status: 401 }, "Version detection failed");
} else {
logger.info(`Version detection failed status=${401}`);
}Acceptance Criteria
- All 144 logger calls updated to use single-line output in plain mode
-
LOG_JSON=false(default): All logs as single-line plain text withkey=valueformat -
LOG_JSON=true: Full structured objects preserved in JSON output - No multiline output visible in
journalctl -u gitlab-mcp - Helper functions created and exported from
src/logger.ts - Existing tests still pass
Testing
# Deploy to staging or run locally
yarn dev:sse
# Check for multiline output (should find NONE)
journalctl -u gitlab-mcp --since "1 minute ago" | grep -E "^\s{4}\w+:"
# Verify JSON mode still works
LOG_JSON=true yarn dev:sse 2>&1 | head -5 | jq .Related
- fix(logging): Access logs output multiline JSON instead of single condensed line #207 - Original fix for access logs only (closed)
- fix(logging): Access logs output single-line format with LOG_JSON mode #208 - JSON logging implementation PR
src/logger.ts-LOG_JSONexportsrc/logging/request-tracker.ts- Example of correct implementation
Reactions are currently unavailable