@cgaspard/webappmcp
Version:
WebApp MCP - Model Context Protocol integration for web applications with server-side debugging tools
266 lines • 9.59 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.interceptBunyan = interceptBunyan;
exports.interceptPino = interceptPino;
exports.interceptLog4js = interceptLog4js;
exports.interceptDebug = interceptDebug;
exports.interceptAllLoggers = interceptAllLoggers;
exports.interceptProcessStreams = interceptProcessStreams;
/**
* Interceptor for Bunyan logger
*/
function interceptBunyan(serverLogs, serverLogLimit) {
try {
const bunyanPath = Object.keys(require.cache).find(key => key.includes('node_modules/bunyan/') && key.endsWith('bunyan.js'));
if (bunyanPath) {
const bunyan = require(bunyanPath);
// Override the _emit method which all log methods use
const originalEmit = bunyan.prototype._emit;
bunyan.prototype._emit = function (rec, noemit) {
if (!noemit) {
serverLogs.push({
level: bunyan.nameFromLevel[rec.level] || 'log',
timestamp: rec.time || new Date().toISOString(),
args: [rec.msg],
metadata: rec,
});
if (serverLogs.length > serverLogLimit) {
serverLogs.shift();
}
}
return originalEmit.call(this, rec, noemit);
};
return true;
}
}
catch (error) {
// Bunyan not found
}
return false;
}
/**
* Interceptor for Pino logger
*/
function interceptPino(serverLogs, serverLogLimit) {
try {
const pinoPath = Object.keys(require.cache).find(key => key.includes('node_modules/pino/') && key.endsWith('pino.js'));
if (pinoPath) {
const pino = require(pinoPath);
// Pino uses a different approach - we need to add a custom transport
// This is more complex and requires pino v7+
const transport = pino.transport({
target: {
write(chunk) {
try {
const log = JSON.parse(chunk);
serverLogs.push({
level: pino.levels.labels[log.level] || 'log',
timestamp: new Date(log.time).toISOString(),
args: [log.msg],
metadata: log,
});
if (serverLogs.length > serverLogLimit) {
serverLogs.shift();
}
}
catch (e) {
// Failed to parse log
}
}
}
});
// Try to attach to default logger
if (pino.destination) {
const originalDestination = pino.destination;
pino.destination = function (...args) {
const dest = originalDestination.apply(pino, args);
// Chain our transport
return {
...dest,
write(chunk) {
transport.write(chunk);
return dest.write(chunk);
}
};
};
}
return true;
}
}
catch (error) {
// Pino not found
}
return false;
}
/**
* Interceptor for log4js
*/
function interceptLog4js(serverLogs, serverLogLimit) {
try {
const log4jsPath = Object.keys(require.cache).find(key => key.includes('node_modules/log4js/') && key.endsWith('log4js.js'));
if (log4jsPath) {
const log4js = require(log4jsPath);
// Create custom appender
const webappMCPAppender = {
configure: () => {
return (loggingEvent) => {
serverLogs.push({
level: loggingEvent.level.levelStr.toLowerCase(),
timestamp: loggingEvent.startTime.toISOString(),
args: loggingEvent.data,
metadata: {
categoryName: loggingEvent.categoryName,
context: loggingEvent.context,
},
});
if (serverLogs.length > serverLogLimit) {
serverLogs.shift();
}
};
}
};
// Register our appender
log4js.configure({
appenders: {
webappMCP: { type: webappMCPAppender }
},
categories: {
default: { appenders: ['webappMCP'], level: 'all' }
}
});
return true;
}
}
catch (error) {
// log4js not found
}
return false;
}
/**
* Interceptor for debug library
*/
function interceptDebug(serverLogs, serverLogLimit) {
try {
const debugPath = Object.keys(require.cache).find(key => key.includes('node_modules/debug/') && key.endsWith('debug.js'));
if (debugPath) {
const debug = require(debugPath);
// Override the log function
const originalLog = debug.log || console.log;
debug.log = function (...args) {
serverLogs.push({
level: 'debug',
timestamp: new Date().toISOString(),
args: args,
});
if (serverLogs.length > serverLogLimit) {
serverLogs.shift();
}
return originalLog.apply(this, args);
};
return true;
}
}
catch (error) {
// debug not found
}
return false;
}
/**
* Try to intercept all known logging libraries based on config
*/
function interceptAllLoggers(serverLogs, serverLogLimit, captureConfig = {}) {
const intercepted = [];
// Default all to true if not specified
const config = {
console: true,
streams: true,
winston: true,
bunyan: true,
pino: true,
debug: true,
log4js: true,
...captureConfig
};
if (config.bunyan && interceptBunyan(serverLogs, serverLogLimit)) {
intercepted.push('bunyan');
}
if (config.pino && interceptPino(serverLogs, serverLogLimit)) {
intercepted.push('pino');
}
if (config.log4js && interceptLog4js(serverLogs, serverLogLimit)) {
intercepted.push('log4js');
}
if (config.debug && interceptDebug(serverLogs, serverLogLimit)) {
intercepted.push('debug');
}
// Check for Winston if enabled
if (config.winston) {
try {
// First try our custom transport approach
const { attachToWinston } = require('./winston-transport');
if (attachToWinston(serverLogs, serverLogLimit)) {
intercepted.push('winston');
}
}
catch (error) {
// Winston transport not available
}
// Also try direct Winston interception as fallback
if (!intercepted.includes('winston')) {
try {
const winston = require('winston');
const { createWinstonTransport } = require('./winston-transport');
const transport = createWinstonTransport(serverLogs, serverLogLimit);
if (transport && winston.loggers && winston.loggers.get) {
// Add to default logger
winston.loggers.get('default').add(transport);
intercepted.push('winston');
}
}
catch (error) {
// Winston not available
}
}
}
return intercepted;
}
/**
* Process.stdout/stderr interception as last resort
*/
function interceptProcessStreams(serverLogs, serverLogLimit) {
const originalStdoutWrite = process.stdout.write;
const originalStderrWrite = process.stderr.write;
process.stdout.write = function (chunk, ...args) {
const text = chunk?.toString ? chunk.toString() : String(chunk);
// Don't capture our own logs
if (!text.includes('[webappmcp]')) {
serverLogs.push({
level: 'log',
timestamp: new Date().toISOString(),
args: [text.trim()],
metadata: { stream: 'stdout' },
});
if (serverLogs.length > serverLogLimit) {
serverLogs.shift();
}
}
return originalStdoutWrite.apply(process.stdout, arguments);
};
process.stderr.write = function (chunk, ...args) {
const text = chunk?.toString ? chunk.toString() : String(chunk);
// Don't capture our own logs
if (!text.includes('[webappmcp]')) {
serverLogs.push({
level: 'error',
timestamp: new Date().toISOString(),
args: [text.trim()],
metadata: { stream: 'stderr' },
});
if (serverLogs.length > serverLogLimit) {
serverLogs.shift();
}
}
return originalStderrWrite.apply(process.stderr, arguments);
};
}
//# sourceMappingURL=logger-interceptors.js.map