<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<springProperty scope="context" name="APP_NAME" source="spring.application.name"/>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/application.log</file>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>logs/application-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxFileSize>10MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>1GB</totalSizeCap>
</rollingPolicy>
</appender>
<appender name="JSON" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
<customFields>{"app":"${APP_NAME}"}</customFields>
</encoder>
</appender>
<springProfile name="dev">
<root level="DEBUG">
<appender-ref ref="CONSOLE"/>
</root>
</springProfile>
<springProfile name="prod">
<root level="INFO">
<appender-ref ref="JSON"/>
<appender-ref ref="FILE"/>
</root>
</springProfile>
<logger name="com.example.demo" level="DEBUG"/>
<logger name="org.springframework" level="INFO"/>
<logger name="org.hibernate" level="WARN"/>
</configuration>
package com.example.demo.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.stereotype.Service;
@Service
public class LoggingService {
private static final Logger logger = LoggerFactory.getLogger(LoggingService.class);
public void processUser(Long userId, String action) {
// Add context to all log statements in this thread
MDC.put("userId", userId.toString());
MDC.put("action", action);
try {
logger.debug("Starting user processing");
logger.info("Processing user with ID: {}", userId);
// Parameterized logging - efficient
logger.info("User {} performed action: {}", userId, action);
// Performance-conscious logging
if (logger.isDebugEnabled()) {
logger.debug("Expensive operation result: {}", expensiveOperation());
}
simulateWork();
logger.info("User processing completed successfully");
} catch (Exception e) {
logger.error("Error processing user {}: {}", userId, e.getMessage(), e);
} finally {
// Always clear MDC
MDC.clear();
}
}
private String expensiveOperation() {
// This only runs if DEBUG is enabled
return "expensive result";
}
private void simulateWork() {
logger.trace("Detailed trace information");
logger.debug("Debug information for developers");
logger.info("Informational message");
logger.warn("Warning: something unexpected but handled");
if (Math.random() < 0.1) {
logger.error("Error occurred in simulation");
}
}
public void demonstrateStructuredLogging() {
logger.info("Event occurred",
org.slf4j.event.KeyValuePair.pair("eventType", "USER_LOGIN"),
org.slf4j.event.KeyValuePair.pair("ipAddress", "192.168.1.1"),
org.slf4j.event.KeyValuePair.pair("success", true));
}
}
SLF4J provides a logging facade, Logback implements it efficiently. I use logger levels—TRACE, DEBUG, INFO, WARN, ERROR—to control verbosity. Parameterized logging with {} placeholders improves performance versus string concatenation. MDC (Mapped Diagnostic Context) adds contextual data like user IDs or request IDs to logs. Appenders direct output—console, files, rolling files, external systems. Patterns format log entries with timestamps, levels, thread names, class names. Async appenders improve throughput. Environment-specific configuration uses Spring profiles. Structured logging outputs JSON for centralized systems like ELK stack. Proper logging enables debugging, monitoring, and audit trails. I avoid logging sensitive data and use appropriate levels—DEBUG for development, INFO for production events, ERROR for failures.
Related snips
type User {
id: ID!
name: String!
email: String!
posts: [Post!]!
createdAt: String!
GraphQL API with Spring Boot
use tracing::{info, instrument};
#[instrument]
fn process_request(user_id: u64) {
info!(user_id, "Processing request");
// Work happens here
tracing for structured logging and distributed tracing
package com.example.starter.config;
import com.example.starter.properties.CustomProperties;
import com.example.starter.service.CustomService;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
Custom Spring Boot starters
package com.example.demo.config;
import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.common.serialization.StringDeserializer;
import org.apache.kafka.common.serialization.StringSerializer;
Messaging with Apache Kafka
import pino, { Logger } from 'pino';
import { AsyncLocalStorage } from 'node:async_hooks';
export interface Store {
requestId: string;
logger: Logger;
Request ID + structured logging (Express + pino)
import logging
import time
logger = logging.getLogger(__name__)
Django middleware for request logging and timing
Share this code
Here's the card — post it anywhere.