Structured Logging é uma abordagem para registro de logs onde cada mensagem é representada em um formato legível por máquina com pares chave-valor, em vez de texto não estruturado. Diferente de strings planas, logs estruturados contêm metadados: timestamp, nível, módulo, ID de requisição — e podem ser indexados por sistemas de análise. De acordo com O'Reilly Effective Logging, a transição para formatos estruturados reduz o tempo de busca de incidentes de horas para minutos graças à possibilidade de filtrar por campos. Este é o padrão de fato no desenvolvimento móvel e de servidores moderno: JSON e logfmt permitem processar logs com programas, não com os olhos.
Pontos principais
Structured Logging é um método de registro de logs onde cada mensagem contém campos nomeados com valores tipados. Em vez de uma string como User 42 logged in from device ABC, um log estruturado parece um conjunto de campos: user_id=42, event=login, device_id=ABC, timestamp=2026-07-04T10:30:00Z.
A principal vantagem dos logs estruturados sobre os textuais é a capacidade de processamento programático. Analisar logs textuais requer expressões regulares e suposições sobre o formato da string. Logs estruturados são analisados sem perda: cada campo tem um tipo e nome conhecidos, permitindo construir consultas como encontrar todos os erros de autenticação da última hora para o usuário 42 sem processamento adicional.
De acordo com Honeycomb.io (2023), equipes que usam structured logging em produção detectam incidentes em média 4 vezes mais rápido em comparação com equipes que dependem de logs textuais e grep.
Structured Logging suporta vários formatos de serialização. A escolha do formato depende da infraestrutura: JSON é conveniente para integração com Elasticsearch e sistemas em nuvem, logfmt para visualização em console via tail e grep, Protocol Buffers para sistemas de alto desempenho com limitações de largura de banda.
| Formato | Exemplo | Quando usar |
|---|---|---|
| JSON | {"event":"login","user_id":42} | ELK Stack, coletores em nuvem, microsserviços |
| Logfmt | event=login user_id=42 duration_ms=150 | Console, tail, heroku logs |
| MessagePack | Equivalente binário do JSON | Sistemas de alta carga, IoT |
JSON é o formato mais comum para logs estruturados. Ele é nativamente suportado por todos os sistemas de coleta: Logstash, Fluentd, Amazon CloudWatch, Google Cloud Logging. Logs JSON são fáceis de ler por humanos e analisar por qualquer linguagem de programação sem bibliotecas adicionais. A principal desvantagem é a verbosidade: cada par chave-valor requer aspas e dois pontos, aumentando o volume de dados armazenados em 30–50% em comparação com logfmt.
Logfmt foi desenvolvido no Heroku para visibilidade em console. É mais compacto que JSON, mantém a legibilidade humana e pode ser facilmente processado com cut e awk. Exemplo: ts=2026-07-04T10:30:00Z level=error module=api status=500. Logfmt não requer escape da maioria dos caracteres e é adequado para logging em stdout em contêineres.
Em aplicativos móveis, Structured Logging resolve três problemas principais: encontrar causas de falhas sem reproduzir no dispositivo, rastrear sessões de usuário e analisar desempenho por versões do aplicativo.
Logs textuais em dispositivos móveis são quase inúteis — um desenvolvedor não pode aplicar grep nos logs do dispositivo do usuário. Logs estruturados são enviados para sistemas em nuvem (Firebase, Sentry, Datadog) e indexados lá. Você pode construir uma consulta como mostrar todos os crashes com iOS 17.4, versão do app 3.2, no módulo de checkout e obter uma seleção precisa em segundos.
De acordo com Sentry (2024), aplicativos que usam breadcrumbs estruturados têm 60% mais contexto em cada relatório de crash em comparação com aplicativos que registram apenas o texto do erro. Isso afeta diretamente a velocidade de correção de bugs.
ELK Stack — Elasticsearch, Logstash, Kibana — continua sendo a infraestrutura padrão para trabalhar com logs estruturados. Logstash recebe logs em JSON, transforma e envia para Elasticsearch para indexação, Kibana fornece uma interface visual para consultas e painéis.
Para aplicativos móveis, soluções em nuvem são populares: Firebase Crashlytics com logs personalizados, Sentry com breadcrumbs, Datadog com rastreamento APM. Eles aceitam logs estruturados diretamente do SDK móvel e não requerem implantação de backend próprio. Firebase oferece um pacote gratuito para relatórios de crash, Sentry adiciona rastreamento distribuído e Datadog integra-se com APM para rastrear o desempenho de requisições tanto no cliente quanto no servidor simultaneamente.
Grafana Loki — uma alternativa ao Elasticsearch otimizada para logs. Loki não indexa o conteúdo das mensagens por padrão, mas usa rótulos (labels) para filtragem. Isso é significativamente mais barato de armazenar e mais rápido para consultas em um conjunto fixo de campos.
// Logging estruturado via Swift Logger em JSON
struct StructuredLog {
let event: String
let attributes: [String: Any]
let level: String
func serialize() -> String {
var base = "event=\(event) level=\(level)"
for (key, value) in attributes {
base += " \(key)=\(value)"
}
return base
}
}
A primeira regra do logging estruturado: cada mensagem deve conter um identificador de requisição ou sessão. Sem contexto, um log individual é inútil — é impossível saber a qual usuário ou requisição pertence. Adicione um correlation ID no início da sessão e passe-o por todas as camadas do aplicativo.
A segunda regra: tipagem de campos. Campos numéricos (duration_ms, status_code, retry_count) devem ser enviados como números, não como strings. Elasticsearch e sistemas similares indexam números e strings de forma diferente: números podem ser agregados (média, mediana, percentil), strings suportam busca de texto completo. Tipagem incorreta impede a criação de painéis analíticos.
A terceira regra: evite objetos aninhados. Logs JSON com profundidade de aninhamento superior a 2 níveis são difíceis de filtrar e visualizar. Em vez de {"user": {"name": "Alice", "role": "admin"}}, use chaves planas: user_name=Alice user_role=admin.
// Logging estruturado no Android via Timber + logfmt
class StructuredTree : Timber.Tree() {
override fun log(priority: Int, tag: String?,
message: String?, t: Throwable?) {
val level = priorityToLevel(priority)
val logfmt = "level=$level tag=$tag message=$message"
sendToRemote(logfmt)
}
}
O conjunto mínimo de campos para cada mensagem estruturada: timestamp em ISO 8601, level (debug/info/warn/error/fatal), logger (nome do módulo ou classe), message (descrição legível do evento). Adicionalmente: correlation_id, user_id (se conhecido), version (versão do app), platform (iOS/Android), environment (dev/staging/prod).
Sem correlation_id, logs estruturados se tornam um conjunto de registros desconexos que não podem ser vinculados em um cenário de usuário único. Gere um UUID a cada inicialização do aplicativo e adicione-o a todos os logs da sessão. Na prática, o correlation_id deve ser transmitido por todas as camadas: de eventos de UI a requisições de rede e tarefas em segundo plano — caso contrário, alguns logs ficarão sem contexto e não participarão da análise. Com rastreamento de ponta a ponta, um único UUID permite coletar a imagem completa da jornada do usuário.
No iOS, o logging estruturado pode ser implementado através de um wrapper sobre os_log que serializa os campos no formato logfmt. No Android, através do Timber com um Tree personalizado que converte mensagens para JSON ou logfmt antes de enviar ao servidor.
import OSLog
struct StructuredLogger {
let subsystem: String
let category: String
func log(level: OSLogType,
event: String,
context: [String: Any]) {
let oslogger = Logger(
subsystem: subsystem,
category: category
)
let fields = context.map {
"\($0.key)=\($0.value)"
}.joined(separator: " ")
oslogger.log(level: level,
"\(event) \(fields)")
}
}
A escolha entre logs estruturados e textuais depende do estágio do projeto. Nos estágios iniciais do desenvolvimento, logs textuais são mais simples e rápidos — o desenvolvedor escreve uma mensagem diretamente sem wrappers adicionais. Mas quando o projeto ultrapassa os limites de uma equipe ou servidor, os logs estruturados se tornam obrigatórios.
| Critério | Logs textuais | Logs estruturados |
|---|---|---|
| Legibilidade | Alta no console | Média (requer pretty-print) |
| Busca | grep por substring | Consultas por campos e valores |
| Agregação | Não suportada | Média, mediana, percentis |
| Integração | Requer análise | Nativa em ELK/Loki/Datadog |
| Volume de armazenamento | Menor (sem metadados) | Maior (campos + valores) |
Perguntas frequentes
Para envio ao servidor, use JSON — ele é nativamente suportado pelo Firebase Crashlytics, Sentry e Datadog. Para visualização local nos logs do Xcode ou Android Studio, use logfmt — é mais compacto e legível sem formatação.
Sim, logs estruturados no cliente permitem adicionar contexto a cada relatório de crash: versão do SO, estado da rede, últimas ações do usuário. Sem breadcrumbs estruturados, um relatório de crash contém apenas a pilha de chamadas sem o cenário do usuário.
Logfmt é mais compacto (30–50% menos volume) e mais fácil de ler em um terminal. JSON suporta objetos e arrays aninhados, mas requer escape de aspas. A escolha depende da infraestrutura: para ELK — JSON, para visualização em console — logfmt.
Crie uma única instância de UUID ao iniciar o aplicativo, armazene-a em um singleton ou contêiner DI e passe-a para todos os loggers através do construtor. Alternativa — use armazenamento local de thread ou Continuation Local Storage em corrotinas Kotlin.
Pode-se, mas não é recomendado — ao misturar, perde-se a capacidade de indexação automática. Se alguns logs são textuais, precisam ser analisados com expressões regulares, o que reduz o desempenho e a confiabilidade da busca. É melhor migrar todos os logs para o formato estruturado.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também