Skip to content

Commit 3bb8c45

Browse files
authored
Improve logging UX for stdio transport and add human-readable console format (#67)
1 parent 6ca838d commit 3bb8c45

5 files changed

Lines changed: 88 additions & 24 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
- Redirect logs to stdout (`stdout` or `console`), stderr (errors/warnings only with `stderr`, or all levels with `stderr-all`), or a custom file path
1616
- Use multiple destinations simultaneously (e.g., `file+console` to log to both file and stdout, or `file+stderr` for file logging with errors to stderr)
1717
- Disable logging entirely with `disabled`
18+
- Improved log readability for console and stderr output by switching from JSON to human-readable format (`YYYY-MM-DD HH:mm:ss.SSS [level] message`), making debugging easier when using `LOG_OUTPUT=console` or `LOG_OUTPUT=stderr-all`. File logging continues to use JSON format for machine parsing
19+
- Added runtime warning when `LOG_OUTPUT=console` or `LOG_OUTPUT=stdout` is used with stdio transport (default for VS Code), guiding users to use `LOG_OUTPUT=stderr-all` or `LOG_OUTPUT=file` instead, as stdout is reserved for MCP protocol communication
20+
- Enhanced documentation with clear guidance on which `LOG_OUTPUT` settings work with stdio transport (VS Code, Claude Desktop) versus HTTP transport, including practical examples for each scenario
1821

1922
## 0.5.3
2023

README.md

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -471,37 +471,47 @@ AWS Lambda Functions:
471471

472472
### Logging Variables
473473

474-
- `LOG_LEVEL` (optional): Log level, writing to dynatrace-managed-mcp.log in the current working directory (e.g. debug, info, warning, error)
475-
- `DT_ENVIRONMENT_CONFIGS`: An escaped JSON array that defines the Dynatrace Managed environment(s) to connect to. See below for contents of this.
476474
- `LOG_LEVEL` (optional): Log verbosity level (e.g. debug, info, warn, error). Default: `info`
477-
- `LOG_OUTPUT` (optional): Log output destination. Options:
478-
- `file` (default): Write logs to a file
479-
- `stdout`: Write logs to standard output
480-
- `console`: Alias for `stdout`
481-
- `stderr`: Write errors and warnings to standard error (info/debug still suppressed)
482-
- `stderr-all`: Write all log levels to standard error
483-
- `file+console` or `file+stdout`: Write logs to both file and stdout
475+
- `LOG_OUTPUT` (optional): Log output destination. Default: `file`
476+
- `file`: Write logs to a file (default behavior)
477+
- `stdout` / `console`: Write logs to standard output (⚠️ **stdio transport only**: Not visible in VS Code Output panel - use `stderr-all` instead)
478+
- `stderr`: Write errors and warnings to standard error (info/debug suppressed)
479+
- `stderr-all`: Write all log levels to standard error (✅ **Recommended for VS Code with stdio transport**)
480+
- `file+console` / `file+stdout`: Write logs to both file and stdout
484481
- `file+stderr`: Write logs to file and errors/warnings to stderr
485482
- `disabled`: Disable logging entirely
486483
- `LOG_FILE` (optional): Path to log file when `LOG_OUTPUT` includes `file`. Default: `dynatrace-managed-mcp.log` in current working directory
487484

485+
> [!IMPORTANT]
486+
> **Choosing the right LOG_OUTPUT for your setup:**
487+
>
488+
> - **VS Code with stdio transport (default)**: Use `LOG_OUTPUT=stderr-all` or `LOG_OUTPUT=file` (default)
489+
> - ❌ `LOG_OUTPUT=console` won't work - stdout is reserved for MCP protocol
490+
> - ✅ `LOG_OUTPUT=stderr-all` shows all logs in VS Code's Output panel
491+
> - ✅ `LOG_OUTPUT=file` writes to log file (read with `tail -f dynatrace-managed-mcp.log`)
492+
> - **HTTP transport (`--http` mode)**: Any `LOG_OUTPUT` option works
493+
> - ✅ `LOG_OUTPUT=console` visible in terminal
494+
> - ✅ `LOG_OUTPUT=stderr-all` visible in terminal
495+
> - ✅ `LOG_OUTPUT=file` writes to log file
496+
488497
**Logging Examples:**
489498

490499
```bash
491-
# Log to standard output (useful for Docker/containerized environments)
492-
LOG_OUTPUT=stdout node dist/index.js
500+
# VS Code with stdio transport - see logs in Output panel
501+
LOG_OUTPUT=stderr-all LOG_LEVEL=debug
493502
494-
# Log errors/warnings to stderr, suppress info/debug (standard Unix practice)
495-
LOG_OUTPUT=stderr node dist/index.js
503+
# VS Code with stdio transport - write to file (default)
504+
LOG_LEVEL=debug
505+
# Read with: tail -f dynatrace-managed-mcp.log
496506
497-
# Log to custom file path
498-
LOG_OUTPUT=file LOG_FILE=/var/log/dynatrace-mcp.log node dist/index.js
507+
# HTTP transport - log to console
508+
LOG_OUTPUT=console LOG_LEVEL=debug node dist/index.js --http
499509
500-
# Log to both file and console (useful for debugging)
501-
LOG_OUTPUT=file+console LOG_LEVEL=debug node dist/index.js
510+
# HTTP transport - log to file and console
511+
LOG_OUTPUT=file+console LOG_LEVEL=debug node dist/index.js --http
502512
503-
# Log to file, send errors/warnings to stderr (production use)
504-
LOG_OUTPUT=file+stderr LOG_FILE=/var/log/app.log node dist/index.js
513+
# Log to custom file path
514+
LOG_OUTPUT=file LOG_FILE=/var/log/dynatrace-mcp.log node dist/index.js
505515
506516
# Disable logging entirely (not recommended)
507517
LOG_OUTPUT=disabled node dist/index.js

package-lock.json

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/index.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1198,6 +1198,20 @@ Never run queries that could return very large amounts of data, or that could be
11981198
// Default stdio mode
11991199
const transport = new StdioServerTransport();
12001200

1201+
// Warn if LOG_OUTPUT is set to stdout/console (won't work with stdio)
1202+
const logOutput = (process.env.LOG_OUTPUT || '').toLowerCase();
1203+
if (
1204+
logOutput === 'console' ||
1205+
logOutput === 'stdout' ||
1206+
logOutput === 'file+console' ||
1207+
logOutput === 'file+stdout'
1208+
) {
1209+
console.error(
1210+
`WARNING: LOG_OUTPUT=${process.env.LOG_OUTPUT} won't show logs in stdio transport. ` +
1211+
`Stdout is reserved for MCP protocol. Use LOG_OUTPUT=stderr-all or LOG_OUTPUT=file instead.`,
1212+
);
1213+
}
1214+
12011215
logger.info('Connecting server to transport...');
12021216
await server.connect(transport);
12031217

src/utils/logger.ts

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,37 @@
11
import winston from 'winston';
22

3+
function createFormat(): winston.Logform.Format {
4+
const logOutput = (process.env.LOG_OUTPUT || 'file').toLowerCase();
5+
const useConsole = [
6+
'console',
7+
'stdout',
8+
'stderr',
9+
'stderr-all',
10+
'file+console',
11+
'file+stdout',
12+
'file+stderr',
13+
].includes(logOutput);
14+
15+
if (useConsole) {
16+
// Use human-readable format for console output
17+
return winston.format.combine(
18+
winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss.SSS' }),
19+
winston.format.errors({ stack: true }),
20+
winston.format.printf(({ timestamp, level, message, ...meta }) => {
21+
const metaStr = Object.keys(meta).length > 0 ? ` ${JSON.stringify(meta)}` : '';
22+
return `${timestamp} [${level}] ${message}${metaStr}`;
23+
}),
24+
);
25+
} else {
26+
// Use JSON format for file output
27+
return winston.format.combine(
28+
winston.format.timestamp(),
29+
winston.format.errors({ stack: true }),
30+
winston.format.json(),
31+
);
32+
}
33+
}
34+
335
function createTransports(): winston.transport[] {
436
const logOutput = (process.env.LOG_OUTPUT || 'file').toLowerCase();
537
const logFile = process.env.LOG_FILE || 'dynatrace-managed-mcp.log';
@@ -45,11 +77,7 @@ function createTransports(): winston.transport[] {
4577

4678
export const logger = winston.createLogger({
4779
level: (process.env.LOG_LEVEL || 'info').toLowerCase(),
48-
format: winston.format.combine(
49-
winston.format.timestamp(),
50-
winston.format.errors({ stack: true }),
51-
winston.format.json(),
52-
),
80+
format: createFormat(),
5381
transports: createTransports(),
5482
});
5583

0 commit comments

Comments
 (0)