Smithery Logo
MCPsSkillsDocsPricing
Login
Smithery Logo

Accelerating the Agent Economy

Resources

DocumentationPrivacy PolicySystem Status

Company

PricingAboutBlog

Connect

© 2026 Smithery. All rights reserved.

    diego-tobalina

    logging

    diego-tobalina/logging
    DevOps
    1 installs

    About

    SKILL.md

    Install

    Install via Skills CLI

    or add to your agent
    • Claude Code
      Claude Code
    • Codex
      Codex
    • OpenClaw
      OpenClaw
    • Cursor
      Cursor
    • Amp
      Amp
    • GitHub Copilot
      GitHub Copilot
    • Gemini CLI
      Gemini CLI
    • Kilo Code
      Kilo Code
    • Junie
      Junie
    • Replit
      Replit
    • Windsurf
      Windsurf
    • Cline
      Cline
    • Continue
      Continue
    • OpenCode
      OpenCode
    • OpenHands
      OpenHands
    • Roo Code
      Roo Code
    • Augment
      Augment
    • Goose
      Goose
    • Trae
      Trae
    • Zencoder
      Zencoder
    • Antigravity
      Antigravity
    ├─
    ├─
    └─

    About

    Logging best practices for Java (SLF4J/Logback) and Node.js (Winston/Pino). Use for structured logging, log levels, and avoiding sensitive data exposure.

    SKILL.md

    Logging Guidelines

    Structured logging best practices for Java and Node.js applications.

    ⚠️ CRITICAL: What NEVER to Log

    Logging sensitive data is a security breach. Never log:

    Authentication & Credentials

    // ❌ NEVER DO THIS - Passwords
    log.info("User login: email={}, password={}", email, password);
    
    // ❌ NEVER DO THIS - Tokens
    log.debug("JWT Token: {}", jwtToken);
    log.info("Authorization: {}", request.getHeader("Authorization"));
    
    // ❌ NEVER DO THIS - API Keys
    log.error("API call failed with key: {}", apiKey);
    
    // ✅ CORRECT - Log identifiers only
    log.info("User login attempt: email={}", maskEmail(email));
    log.debug("Token issued for userId={}", userId);
    

    Personal Identifiable Information (PII)

    // ❌ NEVER DO THIS - Full PII
    log.info("User data: {}", user);  // User object contains SSN, DOB, address
    
    // ❌ NEVER DO THIS - Financial data
    log.info("Payment processed: card={}, cvv={}", cardNumber, cvv);
    
    // ❌ NEVER DO THIS - Personal details
    log.info("Customer: ssn={}, dob={}, phone={}", ssn, dateOfBirth, phone);
    
    // ✅ CORRECT - Log only what you need
    log.info("Payment processed: userId={}, amount={}, last4={}", 
             userId, amount, maskCardLast4(cardNumber));
    

    Health & Sensitive Personal Data

    • Medical records or health information
    • Biometric data (fingerprints, facial recognition)
    • Genetic information
    • Criminal history
    • Sexual orientation or religious beliefs

    Masking Helper Methods

    public class LogMasker {
        public static String maskEmail(String email) {
            if (email == null || !email.contains("@")) return email;
            String[] parts = email.split("@");
            String name = parts[0];
            String domain = parts[1];
            String maskedName = name.length() > 2 
                ? name.substring(0, 2) + "***" 
                : "***";
            return maskedName + "@" + domain;
        }
        
        public static String maskCard(String cardNumber) {
            if (cardNumber == null || cardNumber.length() < 4) return "****";
            return "****-****-****-" + cardNumber.substring(cardNumber.length() - 4);
        }
        
        public static String maskSsn(String ssn) {
            if (ssn == null || ssn.length() < 4) return "***-**-****";
            return "***-**-" + ssn.substring(ssn.length() - 4);
        }
    }
    
    // Usage
    log.info("User registered: email={}, ssn={}", 
             LogMasker.maskEmail(email), 
             LogMasker.maskSsn(ssn));
    // Output: User registered: email=jo***@example.com, ssn=***-**-1234
    

    Node.js Redaction with Pino

    import pino from 'pino';
    
    const logger = pino({
      redact: {
        paths: [
          'password', 
          '*.password',  // password field at any depth
          'token',
          'authorization',
          'apiKey',
          'ssn',
          'creditCard',
          'cvv'
        ],
        remove: true,  // Completely remove (not replace with [Redacted])
      },
    });
    
    // This will NOT log the password
    logger.info({ username: 'john', password: 'secret123' });
    // Output: {"username":"john"}
    

    Core Principles

    1. Use appropriate log levels - Don't spam ERROR for info
    2. Never log sensitive data - No passwords, tokens, PII
    3. Include context - correlation IDs, user IDs, request paths
    4. Structured format - JSON for production, human-readable for dev
    5. Log at boundaries - Entry/exit of services, external calls

    Java Logging (SLF4J + Logback)

    Dependencies

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
    </dependency>
    <!-- For structured logging -->
    <dependency>
        <groupId>net.logstash.logback</groupId>
        <artifactId>logstash-logback-encoder</artifactId>
        <version>7.4</version>
    </dependency>
    

    Basic Usage

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    @Service
    public class UserService {
        private static final Logger log = LoggerFactory.getLogger(UserService.class);
        
        public UserDto createUser(UserCreateDto dto) {
            log.info("Creating user with email: {}", dto.getEmail());
            
            try {
                User user = userRepository.save(mapper.toEntity(dto));
                log.info("User created successfully: id={}", user.getId());
                return mapper.toDto(user);
            } catch (DataIntegrityException e) {
                log.warn("Failed to create user - duplicate email: {}", dto.getEmail());
                throw new DuplicateEmailException(dto.getEmail());
            } catch (Exception e) {
                log.error("Unexpected error creating user: {}", dto.getEmail(), e);
                throw e;
            }
        }
    }
    

    Log Levels

    Level Use For Example
    ERROR Failures requiring immediate attention Database connection lost, payment failed
    WARN Unexpected but handled situations Retry attempt, deprecated API usage
    INFO Significant business events User registered, order placed
    DEBUG Detailed flow for troubleshooting Method entry/exit, variable values
    TRACE Very detailed diagnostic SQL queries, HTTP headers

    Structured Logging (JSON)

    <!-- logback-spring.xml -->
    <configuration>
        <!-- Development: Human readable -->
        <springProfile name="dev">
            <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
                <encoder>
                    <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
                </encoder>
            </appender>
        </springProfile>
        
        <!-- Production: JSON -->
        <springProfile name="prod">
            <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
                <encoder class="net.logstash.logback.encoder.LogstashEncoder">
                    <includeMdcKeyName>correlationId</includeMdcKeyName>
                    <includeMdcKeyName>userId</includeMdcKeyName>
                </encoder>
            </appender>
        </springProfile>
        
        <root level="INFO">
            <appender-ref ref="CONSOLE" />
        </root>
    </configuration>
    
    // Add context with MDC (Mapped Diagnostic Context)
    import org.slf4j.MDC;
    
    @Component
    public class CorrelationIdFilter extends OncePerRequestFilter {
        @Override
        protected void doFilterInternal(HttpServletRequest request, 
                                         HttpServletResponse response, 
                                         FilterChain chain) throws ServletException, IOException {
            String correlationId = request.getHeader("X-Correlation-Id");
            if (correlationId == null) {
                correlationId = UUID.randomUUID().toString();
            }
            
            MDC.put("correlationId", correlationId);
            try {
                chain.doFilter(request, response);
            } finally {
                MDC.clear();
            }
        }
    }
    

    What NOT to Log

    // ❌ WRONG - Never log sensitive data
    log.info("User login: email={}, password={}", email, password);
    log.debug("Credit card: {}", creditCardNumber);
    log.info("Token: {}", jwtToken);
    
    // ❌ WRONG - Don't log at ERROR for expected exceptions
    try {
        userService.findById(id);
    } catch (UserNotFoundException e) {
        log.error("User not found", e); // Should be WARN
        throw e;
    }
    
    // ✅ CORRECT
    log.info("User login attempt: email={}", maskEmail(email));
    log.debug("Processing payment for user={}", userId);
    
    // Mask sensitive data
    private String maskEmail(String email) {
        if (email == null || !email.contains("@")) return email;
        String[] parts = email.split("@");
        return parts[0].substring(0, Math.min(2, parts[0].length())) + "***@" + parts[1];
    }
    

    Node.js Logging (Winston/Pino)

    Winston Setup

    npm install winston
    
    // src/config/logger.ts
    import winston from 'winston';
    
    const { combine, timestamp, json, errors, printf } = winston.format;
    
    // Development format
    const devFormat = printf(({ level, message, timestamp, ...metadata }) => {
        return `${timestamp} [${level}]: ${message} ${
            Object.keys(metadata).length ? JSON.stringify(metadata) : ''
        }`;
    });
    
    export const logger = winston.createLogger({
        level: process.env.LOG_LEVEL || 'info',
        defaultMeta: { 
            service: process.env.APP_NAME || 'app',
            environment: process.env.NODE_ENV 
        },
        format: combine(
            timestamp(),
            errors({ stack: true }),
            process.env.NODE_ENV === 'production' ? json() : devFormat
        ),
        transports: [
            new winston.transports.Console()
        ],
    });
    
    // Add correlation ID
    export const childLogger = (correlationId: string, userId?: string) => {
        return logger.child({ correlationId, userId });
    };
    

    Usage in Express

    // src/middleware/requestLogger.ts
    import { Request, Response, NextFunction } from 'express';
    import { v4 as uuidv4 } from 'uuid';
    import { childLogger } from '../config/logger';
    
    export function requestLogger(req: Request, res: Response, next: NextFunction) {
        const correlationId = req.headers['x-correlation-id'] as string || uuidv4();
        req.correlationId = correlationId;
        req.log = childLogger(correlationId, req.user?.id);
        
        req.log.info({
            method: req.method,
            path: req.path,
            query: req.query,
        }, 'Request started');
        
        const start = Date.now();
        res.on('finish', () => {
            const duration = Date.now() - start;
            req.log.info({
                method: req.method,
                path: req.path,
                statusCode: res.statusCode,
                duration,
            }, 'Request completed');
        });
        
        next();
    }
    
    // Extend Express Request
    declare global {
        namespace Express {
            interface Request {
                correlationId: string;
                log: ReturnType<typeof childLogger>;
            }
        }
    }
    
    // src/services/user.service.ts
    export async function createUser(data: CreateUserDto, req: Request) {
        req.log.info({ email: data.email }, 'Creating user');
        
        try {
            const user = await userRepository.create(data);
            req.log.info({ userId: user.id }, 'User created');
            return user;
        } catch (error) {
            req.log.error({ error, email: data.email }, 'Failed to create user');
            throw error;
        }
    }
    

    Pino (High Performance Alternative)

    npm install pino pino-http
    
    // src/config/logger.ts
    import pino from 'pino';
    
    export const logger = pino({
        level: process.env.LOG_LEVEL || 'info',
        transport: process.env.NODE_ENV !== 'production' 
            ? { target: 'pino-pretty' }
            : undefined,
        base: {
            service: process.env.APP_NAME,
        },
    });
    
    // Express middleware
    import pinoHttp from 'pino-http';
    app.use(pinoHttp({ logger }));
    

    What NOT to Log (Node.js)

    // ❌ WRONG
    logger.info('User login', { email, password }); // Never log passwords!
    logger.debug('Processing payment', { cardNumber, cvv });
    logger.info({ authorization: req.headers.authorization }); // Never log tokens!
    
    // ✅ CORRECT
    logger.info('User login attempt', { email: maskEmail(email) });
    logger.debug('Processing payment', { userId: req.user.id });
    

    Best Practices Summary

    Always Do

    • ✅ Log at service boundaries (entry/exit)
    • ✅ Include correlation IDs for tracing
    • ✅ Log context (userId, requestId) not just messages
    • ✅ Use appropriate log levels
    • ✅ Structure logs as JSON in production
    • ✅ Include timing information for external calls

    Never Do

    • ❌ Log passwords, tokens, credit cards, SSNs
    • ❌ Log PII (email, phone, address) at INFO/ERROR
    • ❌ Use ERROR level for expected exceptions
    • ❌ Log at DEBUG in production (performance)
    • ❌ Log large objects/arrays completely
    • ❌ Use string concatenation in log messages

    Log Entry/Exit Pattern

    // Java
    public Order processOrder(OrderRequest request) {
        log.info("Processing order: userId={}, items={}", 
                 request.getUserId(), 
                 request.getItems().size());
        
        long start = System.currentTimeMillis();
        try {
            Order order = orderService.create(request);
            log.info("Order processed: orderId={}, durationMs={}", 
                     order.getId(), 
                     System.currentTimeMillis() - start);
            return order;
        } catch (Exception e) {
            log.error("Order processing failed: userId={}, error={}", 
                     request.getUserId(), 
                     e.getMessage(), 
                     e);
            throw e;
        }
    }
    
    // Node.js
    async function processOrder(request: OrderRequest, req: Request): Promise<Order> {
        req.log.info({ userId: request.userId, itemCount: request.items.length }, 'Processing order');
        
        const start = Date.now();
        try {
            const order = await orderService.create(request);
            req.log.info({ orderId: order.id, duration: Date.now() - start }, 'Order processed');
            return order;
        } catch (error) {
            req.log.error({ error, userId: request.userId }, 'Order processing failed');
            throw error;
        }
    }
    
    Recommended Servers
    Cloudflare Workers Observability
    Cloudflare Workers Observability
    Vercel
    Vercel
    WorkOS
    WorkOS
    Repository
    diego-tobalina/vibe-coding
    Files