Registro em aplicações Kotlin: melhores práticas na prática
Registro não é apenas escrever mensagens no console. Em aplicações Kotlin modernas (backends de servidor, Android, Ktor, Spring Boot), um registro configurado corretamente é a base para monitoramento, depuração e auditoria. Sem ele, você literalmente trabalha no escuro. Neste artigo, abordaremos as melhores práticas de registro em Kotlin com exemplos reais de código e configurações de nível de produção.
1. Escolha da biblioteca: por que SLF4J + Logback é o padrão da indústria
No mundo JVM, o padrão de facto é SLF4J (Simple Logging Facade for Java) em conjunto com Logback. Kotlin é totalmente compatível com bibliotecas Java, portanto essa combinação funciona nativamente. Para Kotlin, existe um wrapper conveniente chamado kotlin-logging, que adiciona funções de extensão e lazy evaluation inline.
Adicionando dependências (Gradle)
// build.gradle.ktsdependencies { implementation("io.github.microutils:kotlin-logging:3.0.5") implementation("ch.qos.logback:logback-classic:1.4.14")}Uso básico
import mu.KotlinLogging
private val logger = KotlinLogging.logger {}
fun processOrder(orderId: String) { logger.info { "Processamento do pedido $orderId iniciado" } // lógica de negócios logger.debug { "Detalhes do pedido: ${fetchOrderDetails(orderId)}" }}Observe a avaliação lazy (lambda {}): a string só é formada se o nível de registro estiver ativo. Isso é criticamente importante para o desempenho.
2. Níveis de registro: quando usar cada um
A escolha incorreta do nível é um dos erros mais comuns. Use esta tabela como referência rápida:
- ERROR — apenas para erros fatais que exigem intervenção imediata (exceções, perda de dados).
- WARN — situações potencialmente perigosas que não quebram o sistema agora (por exemplo, exceder o limite de tentativas).
- INFO — eventos-chave de negócios: início/parada do serviço, registro bem-sucedido, conclusão de pagamento.
- DEBUG — informações para o desenvolvedor: parâmetros de entrada, estado de objetos, etapas do algoritmo.
- TRACE — detalhamento máximo, geralmente para ativação temporária ao buscar bugs.
Exemplo de uso correto
class PaymentService(private val paymentGateway: PaymentGateway) { private val logger = KotlinLogging.logger {}
fun processPayment(userId: String, amount: BigDecimal): PaymentResult { logger.info { "Pagamento iniciado: userId=$userId, amount=$amount" }
return try { val result = paymentGateway.charge(userId, amount) if (result.success) { logger.info { "Pagamento bem-sucedido: transactionId=${result.transactionId}" } } else { logger.warn { "Pagamento recusado: userId=$userId, reason=${result.reason}" } } result } catch (e: PaymentException) { logger.error(e) { "Erro crítico no gateway de pagamento para userId=$userId" } throw e } }}3. Registro estruturado: JSON e contexto
Sistemas modernos (ELK, Grafana Loki, Datadog) funcionam melhor com logs estruturados. Logback pode escrever em JSON, e Kotlin permite adicionar contexto facilmente através do MDC (Mapped Diagnostic Context).
Configuração do Logback para JSON (logback.xml)
<?xml version="1.0" encoding="UTF-8"?><configuration> <appender name="JSON" class="ch.qos.logback.core.ConsoleAppender"> <encoder class="ch.qos.logback.classic.encoder.JsonEncoder"/> </appender>
<root level="INFO"> <appender-ref ref="JSON"/>