feat: implement comprehensive logging infrastructure (Phases 1-3)
All checks were successful
Build and Push Docker Image to Gitea / build-and-push (push) Successful in 1m50s
All checks were successful
Build and Push Docker Image to Gitea / build-and-push (push) Successful in 1m50s
Added production-ready logging using Pino with structured JSON output, pretty printing in development, and automatic sensitive data redaction. ## Phase 1: Core Logger Setup - Installed pino, pino-http, and pino-pretty dependencies - Created logger utility (lib/utils/logger.ts): - Environment-based log levels (debug in dev, info in prod) - Pretty printing with colors in development - JSON structured logs in production - Sensitive data redaction (passwords, tokens, auth headers) - Custom serializers for errors and requests - Helper functions for child loggers and timing - Added LOG_LEVEL environment variable to .env.example - Configured Next.js for Turbopack with external pino packages ## Phase 2: API Request Logging - Created API logger wrapper (lib/utils/api-logger.ts): - withLogging() HOF for wrapping API route handlers - Automatic request/response logging with timing - Correlation ID generation (X-Request-ID header) - Error catching and structured error responses - logPerformance() helper for timing operations - createApiLogger() for manual logging in routes ## Phase 3: Supervisor Client Logging - Updated lib/supervisor/client.ts: - Added logger instance to SupervisorClient class - Comprehensive XML-RPC call logging (method, params, duration) - Error logging with full context and stack traces - Success logging with result size tracking - DEBUG level logs for all XML-RPC operations - Constructor logging for client initialization ## Configuration Changes - Updated next.config.ts for Turbopack compatibility - Added serverComponentsExternalPackages for pino - Removed null-loader workaround (not needed) ## Features Implemented ✅ Request correlation IDs for tracing ✅ Performance timing for all operations ✅ Sensitive data redaction (passwords, auth) ✅ Environment-based log formatting ✅ Structured JSON logs for production ✅ Pretty colored logs for development ✅ Error serialization with stack traces ✅ Ready for log aggregation (stdout/JSON) ## Next Steps (Phases 4-7) - Update ~30 API routes with logging - Add React Query/hooks error logging - Implement client-side error boundary - Add documentation and testing 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import * as xmlrpc from 'xmlrpc';
|
||||
import { createLogger, formatError } from '../utils/logger';
|
||||
import {
|
||||
ProcessInfo,
|
||||
ProcessInfoSchema,
|
||||
@@ -23,10 +24,18 @@ export interface SupervisorClientConfig {
|
||||
export class SupervisorClient {
|
||||
private client: xmlrpc.Client;
|
||||
private config: SupervisorClientConfig;
|
||||
private logger: ReturnType<typeof createLogger>;
|
||||
|
||||
constructor(config: SupervisorClientConfig) {
|
||||
this.config = config;
|
||||
|
||||
// Create logger with supervisor context
|
||||
this.logger = createLogger({
|
||||
component: 'SupervisorClient',
|
||||
host: config.host,
|
||||
port: config.port,
|
||||
});
|
||||
|
||||
const clientOptions: any = {
|
||||
host: config.host,
|
||||
port: config.port,
|
||||
@@ -39,20 +48,43 @@ export class SupervisorClient {
|
||||
user: config.username,
|
||||
pass: config.password,
|
||||
};
|
||||
this.logger.debug('Basic auth configured');
|
||||
}
|
||||
|
||||
this.client = xmlrpc.createClient(clientOptions);
|
||||
this.logger.info({ config: { host: config.host, port: config.port } }, 'Supervisor client initialized');
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic method call wrapper with error handling
|
||||
* Generic method call wrapper with error handling and logging
|
||||
*/
|
||||
private async call<T>(method: string, params: any[] = []): Promise<T> {
|
||||
const startTime = Date.now();
|
||||
|
||||
// Log the method call
|
||||
this.logger.debug({ method, params }, `Calling XML-RPC method: ${method}`);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
this.client.methodCall(method, params, (error: any, value: any) => {
|
||||
const duration = Date.now() - startTime;
|
||||
|
||||
if (error) {
|
||||
const errorInfo = formatError(error);
|
||||
this.logger.error({
|
||||
method,
|
||||
params,
|
||||
duration,
|
||||
error: errorInfo,
|
||||
}, `XML-RPC call failed: ${method} (${duration}ms) - ${errorInfo.message}`);
|
||||
|
||||
reject(new Error(`XML-RPC Error: ${error?.message || 'Unknown error'}`));
|
||||
} else {
|
||||
this.logger.debug({
|
||||
method,
|
||||
duration,
|
||||
resultSize: JSON.stringify(value).length,
|
||||
}, `XML-RPC call successful: ${method} (${duration}ms)`);
|
||||
|
||||
resolve(value);
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user