En esta guía (6 elementos)
Observability — Structured Logging
Observability — Structured Logging
Project-agnostic. Part of the Observability suite. Covers: SLF4J + Logback configuration, OTEL trace-id correlation in logs, JSON structured logging for production, logging rules and PII guards.
Replace
com.example.platform/platform-serviceplaceholders with your project’s actual package and service name when applying patterns.
Security tie-in: never log secrets, tokens, PII, or full request bodies. See security.md §10.
Companion files:
- observability.md — index + three-pillars overview.
- obs-metrics.md — Micrometer + Prometheus + decorator metrics.
- obs-tracing.md — OTEL tracing.
- obs-recipes.md — step-by-step + dashboards + alerting + checklist.
8. Structured Logging
SLF4J + Logback Configuration with OTEL Trace Correlation
The project uses SLF4J with Logback. Trace correlation is automatic via Micrometer Tracing’s MDC integration.
Current Log Pattern (application.yml)
logging: pattern: console: "%d{HH:mm:ss.SSS} [%thread] [trace-id=%X{traceId}] %-5level %logger{5} - %msg%n" file: "%d{HH:mm:ss.SSS} [%thread] [trace-id=%X{traceId}] %-5level %logger{5} - %msg%n"JSON Structured Logging (Recommended for Production)
For production environments, use JSON-formatted logs for better parsing by log aggregators (ELK, Loki, NewRelic Logs):
Add the dependency to bootstrap/build.gradle.kts:
dependencies { // Logback JSON encoder for structured logging implementation("ch.qos.logback.contrib:logback-json-classic:0.1.5") implementation("ch.qos.logback.contrib:logback-jackson:0.1.5") // OR use Logstash encoder (more common): implementation("net.logstash.logback:logstash-logback-encoder:8.0")}Create bootstrap/src/main/resources/logback-spring.xml:
<?xml version="1.0" encoding="UTF-8"?><configuration>
<springProfile name="local,dev"> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{HH:mm:ss.SSS} [%thread] [trace-id=%X{traceId}] [span-id=%X{spanId}] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <root level="INFO"> <appender-ref ref="CONSOLE"/> </root> </springProfile>
<springProfile name="staging,production"> <appender name="CONSOLE_JSON" class="ch.qos.logback.core.ConsoleAppender"> <encoder class="net.logstash.logback.encoder.LogstashEncoder"> <includeMdcKeyName>traceId</includeMdcKeyName> <includeMdcKeyName>spanId</includeMdcKeyName> <customFields> {"service":"platform-service"} </customFields> </encoder> </appender> <root level="INFO"> <appender-ref ref="CONSOLE_JSON"/> </root> </springProfile>
</configuration>Logging Examples
Kotlin:
import org.slf4j.LoggerFactory
class CreateUserUseCase( private val userRepository: UserRepositoryPort,) : CreateUserPort {
companion object { private val log = LoggerFactory.getLogger(CreateUserUseCase::class.java) }
override fun execute(command: CreateUserCommand): User { log.info("Creating user id={}", command.userId) val user = userRepository.save(command.toUser()) log.info("User created successfully with id={}", user.id) return user }}Java:
import org.slf4j.Logger;import org.slf4j.LoggerFactory;
public class CreateUserUseCase implements CreateUserPort {
private static final Logger log = LoggerFactory.getLogger(CreateUserUseCase.class);
private final UserRepositoryPort userRepository;
public CreateUserUseCase(UserRepositoryPort userRepository) { this.userRepository = userRepository; }
@Override public User execute(CreateUserCommand command) { log.info("Creating user id={}", command.userId()); User user = userRepository.save(command.toUser()); log.info("User created successfully with id={}", user.getId()); return user; }}Logging Rules
- Use parameterized messages (
log.info("msg {}", value)) — never string concatenation. - Never log sensitive data (passwords, tokens, PII beyond what is strictly necessary).
- Include domain context (entity IDs, operation names) for traceability.
- Log at the right level:
ERROR: Unrecoverable failures that need immediate attention.WARN: Recoverable issues or degraded behavior.INFO: Significant business events (created, updated, deleted).DEBUG: Detailed diagnostic information (cache hits, query parameters).
- The trace-id is automatically included in every log line via MDC — do not log it manually.