Enable file logging (writing to mcp-server/logs at info level by default)

This commit is contained in:
Dominik Jain 2025-11-29 22:38:52 +01:00
parent f01774ab6b
commit 60acaec396
3 changed files with 85 additions and 25 deletions

4
.gitignore vendored
View File

@ -5,3 +5,7 @@ dist
*.orig
temp
*.tsbuildinfo
# Log files
logs/
*.log

View File

@ -1,7 +1,7 @@
#!/usr/bin/env node
import { PenpotMcpServer } from "./PenpotMcpServer";
import { createLogger } from "./logger";
import { createLogger, logFilePath } from "./logger";
/**
* Entry point for Penpot MCP Server
@ -10,18 +10,20 @@ import { createLogger } from "./logger";
* gracefully and ensuring proper process termination.
*
* Usage:
* - Default port: node dist/index.js (runs on 4401)
* - Custom port: node dist/index.js --port <port>
* - Help: node dist/index.js --help
* - Default configuration: runs on port 4401, logs to mcp-server/logs at info level
*/
async function main(): Promise<void> {
const logger = createLogger("main");
try {
// Parse command line arguments for port configuration
const args = process.argv.slice(2);
let port = 4401; // Default port
// log the file path early so it appears before any potential errors
logger.info(`Logging to file: ${logFilePath}`);
try {
const args = process.argv.slice(2);
let port = 4401; // default port
// parse command line arguments
for (let i = 0; i < args.length; i++) {
if (args[i] === "--port" || args[i] === "-p") {
if (i + 1 < args.length) {
@ -32,10 +34,20 @@ async function main(): Promise<void> {
logger.info("Invalid port number. Using default port 4401.");
}
}
} else if (args[i] === "--log-level" || args[i] === "-l") {
if (i + 1 < args.length) {
process.env.LOG_LEVEL = args[i + 1];
}
} else if (args[i] === "--log-dir") {
if (i + 1 < args.length) {
process.env.LOG_DIR = args[i + 1];
}
} else if (args[i] === "--help" || args[i] === "-h") {
logger.info("Usage: node dist/index.js [options]");
logger.info("Options:");
logger.info(" --port, -p <number> Port number for the HTTP/SSE server (default: 4401)");
logger.info(" --log-level, -l <level> Log level: trace, debug, info, warn, error (default: info)");
logger.info(" --log-dir <path> Directory for log files (default: mcp-server/logs)");
logger.info(" --help, -h Show this help message");
process.exit(0);
}
@ -44,7 +56,7 @@ async function main(): Promise<void> {
const server = new PenpotMcpServer(port);
await server.start();
// Keep the process alive
// keep the process alive
process.on("SIGINT", async () => {
logger.info("Received SIGINT, shutting down gracefully...");
await server.stop();

View File

@ -1,27 +1,71 @@
import pino from "pino";
import { join, resolve } from "path";
/**
* Logger instance configured for console output with metadata.
* Configuration for log file location and level.
*/
const LOG_DIR = process.env.LOG_DIR || "logs";
const LOG_LEVEL = process.env.LOG_LEVEL || "info";
/**
* Generates a timestamped log file name.
*
* Configured to output to console only with level, full timestamp, origin, and message.
* @returns Log file name
*/
function generateLogFileName(): string {
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, "0");
const day = String(now.getDate()).padStart(2, "0");
const hours = String(now.getHours()).padStart(2, "0");
const minutes = String(now.getMinutes()).padStart(2, "0");
const seconds = String(now.getSeconds()).padStart(2, "0");
return `penpot-mcp-${year}${month}${day}-${hours}${minutes}${seconds}.log`;
}
/**
* Absolute path to the log file being written.
*/
export const logFilePath = resolve(join(LOG_DIR, generateLogFileName()));
/**
* Logger instance configured for both console and file output with metadata.
*
* Both console and file output use pretty formatting for human readability.
* Console output includes colors, while file output is plain text.
*/
export const logger = pino({
level: "info",
level: LOG_LEVEL,
timestamp: pino.stdTimeFunctions.isoTime,
formatters: {
level: (label) => {
return { level: label };
},
},
transport: {
target: "pino-pretty",
options: {
colorize: true,
translateTime: "SYS:yyyy-mm-dd HH:MM:ss.l",
ignore: "pid,hostname",
messageFormat: "{msg}",
levelFirst: true,
},
targets: [
{
// console transport with pretty formatting
target: "pino-pretty",
level: LOG_LEVEL,
options: {
colorize: true,
translateTime: "SYS:yyyy-mm-dd HH:MM:ss.l",
ignore: "pid,hostname",
messageFormat: "{msg}",
levelFirst: true,
},
},
{
// file transport with pretty formatting (same as console)
target: "pino-pretty",
level: LOG_LEVEL,
options: {
destination: logFilePath,
colorize: false,
translateTime: "SYS:yyyy-mm-dd HH:MM:ss.l",
ignore: "pid,hostname",
messageFormat: "{msg}",
levelFirst: true,
mkdir: true,
},
},
],
},
});