Skip to main content

logging-patterns

Java logging best practices with SLF4J, structured logging (JSON), and MDC for request tracing. Includes AI-friendly log formats for Claude Code debugging. Use when user asks about logging, debugging application flow, or analyzing logs.

Informações da origem

Repositório
piomin/spring-boot-istio
Última atividade na origem
5 de março de 2026 às 11:20
Idioma detectado do SKILL.md
inglês
Estrelas
70
Forks
22

Opções de instalação

Por padrão, está selecionado o prompt que primeiro revisa a origem. Você pode mudar para um comando direto ou baixar uma cópia local.

Revise os arquivos de origem

Leia o SKILL.md e os arquivos complementares exibidos pelo SkillsMP antes de decidir se vai instalar.

Explorador de arquivos
2 arquivos

Exibindo SKILL.md

SKILL.md
Instruções da origem · Visualização somente leitura
name
logging-patterns
description
Java logging best practices with SLF4J, structured logging (JSON), and MDC for request tracing. Includes AI-friendly log formats for Claude Code debugging. Use when user asks about logging, debugging application flow, or analyzing logs.
# Logging Patterns Skill Effective logging for Java applications with focus on structured, AI-parsable formats. ## When to Use - User says "add logging" / "improve logs" / "debug this" - Analyzing application flow from logs - Setting up structured logging (JSON) - Request tracing with correlation IDs - AI/Claude Code needs to analyze application behavior --- ## AI-Friendly Logging > **Key insight:** JSON logs are better for AI analysis - faster parsing, fewer tokens, direct field access. ### Why JSON for AI/Claude Code? ``` # Text format - AI must "interpret" the string 2026-01-29 10:15:30 INFO OrderService - Order 12345 created for user-789, total: 99.99 # JSON format - AI extracts fields directly {"timestamp":"2026-01-29T10:15:30Z","level":"INFO","orderId":12345,"userId":"user-789","total":99.99} ``` | Aspect | Text | JSON | |--------|------|------| | Parsing | Regex/interpretation | Direct field access | | Token usage | Higher (repeated patterns) | Lower (structured) | | Error extraction | Parse stack trace text | `exception` field | | Filtering | grep patterns | `jq` queries | ### Recommended Setup for AI-Assisted Development ```yaml # application.yml - JSON by default logging: structured: format: console: logstash # Spring Boot 3.4+ # When YOU need to read logs manually: # Option 1: Use jq # tail -f app.log | jq . # Option 2: Switch profile temporarily # java -jar app.jar --spring.profiles.active=human-logs ``` ### Log Format Optimized for AI Analysis ```json { "timestamp": "2026-01-29T10:15:30.123Z", "level": "INFO", "logger": "com.example.OrderService", "message": "Order created", "requestId": "req-abc123", "traceId": "trace-xyz", "orderId": 12345, "userId": "user-789", "duration_ms": 45, "step": "payment_completed" } ``` **Key fields for AI debugging:** - `requestId` - group all logs from same request - `step` - track progress through flow - `duration_ms` - identify slow operations - `level` - quick filter for errors ### Reading Logs with AI/Claude Code When asking AI to analyze logs: ```bash # Get recent errors cat app.log | jq 'select(.level == "ERROR")' | tail -20 # Follow specific request cat app.log | jq 'select(.requestId == "req-abc123")' # Find slow operations cat app.log | jq 'select(.duration_ms > 1000)' ``` AI can then: 1. Parse JSON directly (no guessing) 2. Follow request flow via requestId 3. Identify exactly where errors occurred 4. Measure timing between steps --- ## Quick Setup (Spring Boot 3.4+) ### Native Structured Logging Spring Boot 3.4+ has built-in support - no extra dependencies! ```yaml # application.yml logging: structured: format: console: logstash # or "ecs" for Elastic Common Schema # Supported formats: logstash, ecs, gelf ``` ### Profile-Based Switching ```yaml # application.yml (default - JSON for AI/prod) spring: profiles: default: json-logs --- spring: config: activate: on-profile: json-logs logging: structured: format: console: logstash --- spring: config: activate: on-profile: human-logs # No structured format = human-readable default logging: pattern: console: "%d{HH:mm:ss.SSS} %-5level [%thread] %logger{36} - %msg%n" ``` **Usage:** ```bash # Default: JSON (for AI, CI/CD, production) ./mvnw spring-boot:run # Human-readable when needed ./mvnw spring-boot:run -Dspring.profiles.active=human-logs ``` --- ## Setup for Spring Boot < 3.4 ### Logstash Logback Encoder **pom.xml:** ```xml <dependency> <groupId>net.logstash.logback</groupId> <artifactId>logstash-logback-encoder</artifactId> <version>7.4</version> </dependency> ``` **logback-spring.xml:** ```xml <?xml version="1.0" encoding="UTF-8"?> <configuration> <!-- JSON (default) --> <springProfile name="!human-logs"> <appender name="JSON" class="ch.qos.logback.core.ConsoleAppender"> <encoder class="net.logstash.logback.encoder.LogstashEncoder"> <includeMdcKeyName>requestId</includeMdcKeyName> <includeMdcKeyName>userId</includeMdcKeyName> </encoder> </appender> <root level="INFO"> <appender-ref ref="JSON"/> </root> </springProfile> <!-- Human-readable (optional) --> <springProfile name="human-logs"> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{HH:mm:ss.SSS} %-5level [%thread] %logger{36} - %msg%n</pattern> </encoder> </appender> <root level="INFO"> <appender-ref ref="CONSOLE"/> </root> </springProfile> </configuration> ``` ### Adding Custom Fields (Logstash Encoder) ```java import static net.logstash.logback.argument.StructuredArguments.kv; // Fields appear as separate JSON keys log.info("Order created", kv("orderId", order.getId()), kv("userId", user.getId()), kv("total", order.getTotal()), kv("step", "order_created") ); // Output: // {"message":"Order created","orderId":123,"userId":"u-456","total":99.99,"step":"order_created"} ``` --- ## SLF4J Basics ### Logger Declaration ```java import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Service public class OrderService { private static final Logger log = LoggerFactory.getLogger(OrderService.class); } // Or with Lombok @Slf4j @Service public class OrderService { // use `log` directly } ``` ### Parameterized Logging ```java // ✅ GOOD: Evaluated only if level enabled log.debug("Processing order {} for user {}", orderId, userId); // ❌ BAD: Always concatenates log.debug("Processing order " + orderId + " for user " + userId); // ✅ For expensive operations if (log.isDebugEnabled()) { log.debug("Full order details: {}", order.toJson()); } ``` --- ## Log Levels | Level | When | Example | |-------|------|---------| | **ERROR** | Failures needing attention | Unhandled exception, service down | | **WARN** | Unexpected but handled | Retry succeeded, deprecated API used | | **INFO** | Business events | Order created, payment processed | | **DEBUG** | Technical details | Method params, SQL queries | | **TRACE** | Very detailed | Loop iterations (rarely used) | ```java log.error("Payment failed", kv("orderId", id), kv("reason", reason), exception); log.warn("Retry succeeded", kv("attempt", 3), kv("orderId", id)); log.info("Order shipped", kv("orderId", id), kv("trackingNumber", tracking)); log.debug("Fetching from DB", kv("query", "findById"), kv("id", id)); ``` --- ## MDC (Mapped Diagnostic Context) MDC adds context to every log entry in a request - essential for tracing. ### Request ID Filter ```java @Component @Order(Ordered.HIGHEST_PRECEDENCE) public class RequestContextFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { try { String requestId = Optional.ofNullable(request.getHeader("X-Request-ID")) .filter(s -> !s.isBlank()) .orElse(UUID.randomUUID().toString().substring(0, 8)); MDC.put("requestId", requestId); response.setHeader("X-Request-ID", requestId); chain.doFilter(request, response); } finally { MDC.clear(); } } } ``` ### Add User Context ```java // After authentication MDC.put("userId", authentication.getName()); // All subsequent logs include userId automatically log.info("User action performed"); // {"userId":"john123","message":"User action performed"} ``` ### MDC in Async Operations ```java // MDC doesn't auto-propagate to new threads! // ✅ Copy MDC context Map<String, String> context = MDC.getCopyOfContextMap(); CompletableFuture.runAsync(() -> { try { if (context != null) MDC.setContextMap(context); log.info("Async task running"); // Has requestId, userId } finally { MDC.clear(); } }); ``` --- ## What to Log ### Business Events (INFO) ```java // Include key identifiers and state log.info("Order created", kv("orderId", id), kv("userId", userId), kv("total", total), kv("itemCount", items.size()), kv("step", "order_created")); log.info("Payment processed", kv("orderId", id), kv("amount", amount), kv("method", "card"), kv("step", "payment_completed")); ``` ### External Calls (with timing) ```java long start = System.currentTimeMillis(); try { Result result = externalService.call(params); log.info("External call succeeded", kv("service", "PaymentGateway"), kv("operation", "charge"), kv("duration_ms", System.currentTimeMillis() - start)); return result; } catch (Exception e) { log.error("External call failed", kv("service", "PaymentGateway"), kv("operation", "charge"), kv("duration_ms", System.currentTimeMillis() - start), e); throw e; } ``` ### Flow Steps (for AI tracing) ```java public Order processOrder(CreateOrderRequest request) { log.info("Processing started", kv("step", "start"), kv("requestData", request.summary())); Order order = createOrder(request); log.info("Order created", kv("step", "order_created"), kv("orderId", order.getId())); validateInventory(order); log.info("Inventory validated", kv("step", "inventory_ok"), kv("orderId", order.getId())); processPayment(order); log.info("Payment processed", kv("step", "payment_done"), kv("orderId", order.getId())); log.info("Processing completed", kv("step", "complete"), kv("orderId", order.getId())); return order; } ``` ---
Ver no GitHub
Este SKILL.md e muito grande, entao o SkillsMP mostra aqui apenas a primeira secao. Ver no GitHub