Bibliotecas de Logging em Zig — Registro Estruturado e Diagnóstico
Logging adequado é essencial para qualquer aplicação em produção. O Zig aborda logging de forma única: a biblioteca padrão inclui um sistema de logging integrado que é avaliado em tempo de compilação, permitindo que logs de debug sejam completamente removidos em builds de release sem custo algum. Além disso, o ecossistema oferece bibliotecas de terceiros para logging estruturado avançado.
std.log — O Sistema Integrado
O std.log é o sistema de logging da biblioteca padrão do Zig. Suas principais vantagens são a avaliação em comptime e a eliminação de código morto pelo compilador:
const std = @import("std");
const log = std.log;
pub fn main() void {
log.info("Aplicação iniciada na porta {}", .{8080});
log.debug("Detalhes internos: buffer_size={}", .{4096});
log.warn("Conexão lenta detectada: latência={}ms", .{500});
log.err("Falha ao conectar ao banco de dados: {s}", .{"connection refused"});
}
Níveis de Log
O std.log define quatro níveis, do mais verboso ao mais crítico:
// Do mais verboso ao mais severo
log.debug("..."); // Informações de desenvolvimento
log.info("..."); // Eventos normais de operação
log.warn("..."); // Situações anômalas mas não fatais
log.err("..."); // Erros que afetam funcionalidade
Escopos de Log
Defina escopos para categorizar mensagens por módulo:
const std = @import("std");
// Escopo customizado
const db_log = std.log.scoped(.database);
const http_log = std.log.scoped(.http);
const auth_log = std.log.scoped(.auth);
pub fn conectarBanco() !void {
db_log.info("Conectando ao PostgreSQL em {s}:{}", .{ "localhost", 5432 });
// ...
db_log.info("Conexão estabelecida com sucesso", .{});
}
pub fn processarRequisicao() !void {
http_log.debug("Recebida requisição GET /api/usuarios", .{});
// ...
http_log.info("Requisição processada em {}ms", .{42});
}
pub fn autenticar(usuario: []const u8) !void {
auth_log.info("Tentativa de login: {s}", .{usuario});
// ...
auth_log.warn("Login falhou para {s}: senha incorreta", .{usuario});
}
Configuração de Nível de Log
Controle quais níveis são ativos em tempo de compilação:
// Na raiz do módulo (root.zig ou main.zig)
pub const std_options = struct {
// Definir nível mínimo de log
pub const log_level: std.log.Level = .debug; // Em dev
// pub const log_level: std.log.Level = .info; // Em produção
// Filtrar por escopo
pub const log_scope_levels = &[_]std.log.ScopeLevel{
.{ .scope = .database, .level = .warn },
.{ .scope = .http, .level = .info },
.{ .scope = .auth, .level = .debug },
};
};
Função de Log Customizada
Substitua a implementação padrão de log:
pub const std_options = struct {
pub const logFn = meuLogCustomizado;
};
fn meuLogCustomizado(
comptime nivel: std.log.Level,
comptime escopo: @TypeOf(.enum_literal),
comptime formato: []const u8,
args: anytype,
) void {
const prefixo_nivel = comptime switch (nivel) {
.debug => "DEBUG",
.info => "INFO ",
.warn => "WARN ",
.err => "ERROR",
};
const prefixo_escopo = if (escopo != .default)
"[" ++ @tagName(escopo) ++ "] "
else
"";
const timestamp = std.time.timestamp();
std.debug.print(
"{} {s} {s}" ++ formato ++ "\n",
.{timestamp} ++ .{prefixo_nivel} ++ .{prefixo_escopo} ++ args,
);
}
Logging Estruturado
Para aplicações que precisam de logs estruturados (JSON, logfmt), bibliotecas de terceiros complementam a std:
zig-log (Logging JSON)
const zlog = @import("zig-log");
pub fn main() !void {
var logger = try zlog.Logger.init(.{
.format = .json,
.output = .stderr,
.level = .info,
});
defer logger.deinit();
logger.info("Requisição processada", .{
.method = "GET",
.path = "/api/usuarios",
.status = 200,
.duracao_ms = 42,
.ip = "192.168.1.100",
});
// Saída: {"level":"info","msg":"Requisição processada","method":"GET","path":"/api/usuarios","status":200,"duracao_ms":42,"ip":"192.168.1.100","timestamp":"2026-02-21T10:30:00Z"}
}
Logging para Arquivo com Rotação
const FileLogger = struct {
arquivo: std.fs.File,
max_tamanho: usize,
tamanho_atual: usize,
caminho_base: []const u8,
pub fn init(caminho: []const u8, max_tamanho: usize) !FileLogger {
const arquivo = try std.fs.cwd().createFile(caminho, .{ .truncate = false });
const stat = try arquivo.stat();
return FileLogger{
.arquivo = arquivo,
.max_tamanho = max_tamanho,
.tamanho_atual = stat.size,
.caminho_base = caminho,
};
}
pub fn log(self: *FileLogger, comptime fmt: []const u8, args: anytype) !void {
const msg = try std.fmt.allocPrint(
std.heap.page_allocator,
fmt ++ "\n",
args,
);
defer std.heap.page_allocator.free(msg);
if (self.tamanho_atual + msg.len > self.max_tamanho) {
try self.rotacionar();
}
try self.arquivo.writeAll(msg);
self.tamanho_atual += msg.len;
}
fn rotacionar(self: *FileLogger) !void {
self.arquivo.close();
// Renomear arquivo atual
var buf: [256]u8 = undefined;
const novo_nome = try std.fmt.bufPrint(&buf, "{s}.{}", .{
self.caminho_base,
std.time.timestamp(),
});
try std.fs.cwd().rename(self.caminho_base, novo_nome);
self.arquivo = try std.fs.cwd().createFile(self.caminho_base, .{});
self.tamanho_atual = 0;
}
};
Integração com Sistemas Externos
Syslog
const posix = std.posix;
fn logParaSyslog(mensagem: []const u8) void {
const sock = posix.socket(posix.AF.UNIX, posix.SOCK.DGRAM, 0) catch return;
defer posix.close(sock);
const addr = posix.sockaddr.un{ .path = "/dev/log" };
_ = posix.sendto(sock, mensagem, 0, &addr, @sizeOf(@TypeOf(addr))) catch {};
}
Boas Práticas
- Use escopos: Categorize logs por módulo para facilitar filtragem
- Nível apropriado: Use
debugpara desenvolvimento,infopara operação,warnpara anomalias,errpara falhas - Logs estruturados em produção: JSON facilita parsing por ferramentas como ELK e Datadog
- Não logue dados sensíveis: Nunca registre senhas, tokens ou dados pessoais
- Contexto suficiente: Inclua IDs de request, timestamps e metadata relevante
- Configure por ambiente: Debug em dev, info em staging, warn/err em produção
Próximos Passos
Combine logging com as ferramentas de debug para diagnóstico avançado, as ferramentas de profiling para correlacionar logs com performance, e os frameworks de teste para verificar comportamento de logging. Consulte nossos tutoriais para exemplos práticos.