Por que uma aplicação Kotlin "silenciosa" é uma bomba-relógio
\n\nImagine: você colocou um serviço em Kotlin no ar, ele funciona perfeitamente. Os usuários estão satisfeitos, as métricas estão verdes. Mas um belo dia, a carga aumenta, a latência dispara, e você não faz ideia do porquê. Sem logging e monitoramento, você é um capitão de navio sem mapa e radar. Neste artigo, vamos mostrar como transformar sua aplicação de uma "caixa-preta" em um sistema transparente, onde cada falha fica visível a olho nu.
\n\nNão vamos apenas copiar a documentação. Em vez disso, traremos casos reais, snippets prontos e soluções arquiteturais que funcionam em produção. Vamos nessa.
\n\nDividindo o problema: logging vs monitoramento
\n\nAntes de escrever código, vamos alinhar os conceitos. Logging é o registro de eventos (erros, avisos, informações de depuração) em formato estruturado ou textual. Monitoramento é a coleta de métricas (tempo de resposta, número de requisições, uso de CPU) e sua visualização. Idealmente, eles trabalham juntos: logs são para análise profunda de incidentes, métricas são para detecção rápida de anomalias.
\n\nConfigurando logging em Kotlin: do básico ao avançado
\n\nEscolhendo a biblioteca: SLF4J + Logback — o padrão ouro
\n\nKotlin se integra perfeitamente com o ecossistema Java, então SLF4J (fachada) e Logback (implementação) são a escolha número 1. Eles são leves, performáticos e suportam logging assíncrono.
\n\nAdicione ao build.gradle.kts:
implementation("ch.qos.logback:logback-classic:1.4.14")\nimplementation("io.github.microutils:kotlin-logging-jvm:3.0.5")\n\nkotlin-logging é uma camada fina sobre o SLF4J que deixa o código mais limpo. Compare:
\n\nSem a biblioteca:
\nprivate val logger = LoggerFactory.getLogger(MyService::class.java)\nlogger.info("User {} logged in", userId)\n\nCom kotlin-logging:
\nprivate val logger = KotlinLogging.logger {}\nlogger.info { "User $userId logged in" }\n\nA avaliação preguiçosa da string é um bônus para performance: a string só será montada se o nível de logging estiver ativo.
\n\nConfiguração do Logback: logs estruturados são obrigatórios
\n\nCrie o arquivo logback.xml em src/main/resources:
<configuration>\n <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">\n <encoder class="net.logstash.logback.encoder.LogstashEncoder"/>\n </appender>\n\n <root level="INFO">\n <appender-ref ref="CONSOLE"/>\n </root>\n</configuration>\n\nEstamos usando o LogstashEncoder — ele transforma os logs em JSON. Isso é essencial se você envia logs para Elasticsearch, Loki ou qualquer outro agregador. Logs em JSON são fáceis de parsear, filtrar e analisar.
\n\nNão esqueça de adicionar a dependência:
\nimplementation("net.logstash.logback:logstash-logback-encoder:7.4")\n\nEscrevendo logs com significado: contexto é tudo
\n\nLogs como "Ocorreu um erro" são inúteis. Adicione o MDC (Mapped Diagnostic Context) — é como colocar tags nos seus logs.
import org.slf4j.MDC\n\nclass OrderService {\n private val logger = KotlinLogging.logger {}\n\n fun processOrder(orderId: String, userId: String) {\n MDC.put("orderId", orderId)\n MDC.put("userId", userId)\n try {\n logger.info { "Processando pedido" }\n // lógica de negócio\n } catch (e: Exception) {\n logger.error(e) { "Falha ao processar pedido" }\n } finally {\n MDC.clear()\n }\n }\n}\n\nAgora, no seu agregador de logs, você consegue encontrar todos os registros de um pedido ou usuário específico em segundos.
\n\n