Loguinho 🪵
Loguinho é um framework moderno, seguro, de alta performance e multiplataforma de logging estruturado para aplicações Dart e Flutter.
Ele resolve os maiores problemas de logging em aplicações reais: vazamento involuntário de dados sensíveis (PII) em logs do console, engasgos na interface do usuário (UI Thread drops de FPS) por escrita síncrona I/O e falta de rastreabilidade de sessões.
✨ Principais Recursos
- 🛡️ Sanitização Automática de PII: Mascara automaticamente CPFs, e-mails, números de cartão de crédito e senhas antes de registrar o log.
- 🎨 Formatação Adaptativa: Layout limpo e colorido com ANSI no terminal em Desenvolvimento; JSON estruturado pronto para observabilidade em Produção.
- ⚡ Zero FPS Impact: Processamento assíncrono e lazy formatting que impede quedas de quadros na UI Thread do Flutter.
- 🧭 Contexto de Sessão e W3C Trace: Suporte nativo a
sessionId,userId,traceIdespanIdpara integração com OpenTelemetry e Grafana/Datadog. - 🚦 Configurações Prontas por Ambiente: Modos pré-configurados para
development,stageeproduction. - 🧩 Arquitetura Extensível (SOLID): Suporte a múltiplos destinos (
ConsoleOutput,MemoryBufferOutput) e formatadores customizados.
🚀 Como Adicionar ao Seu Projeto
Opção 1: Via pub.dev (Comando CLI)
Execute o comando no terminal na raiz do seu projeto:
# Para projetos Flutter:
flutter pub add loguinho
# Para projetos Dart:
dart pub add loguinho
Opção 2: Edição Manual no pubspec.yaml
Adicione o Loguinho com sua versão na seção dependencies do seu pubspec.yaml:
dependencies:
flutter:
sdk: flutter
# Instalação via pub.dev:
loguinho: ^1.0.0
# Ou instalação direta via repositório GitHub:
# loguinho:
# git:
# url: https://github.com/flubit-dev/loguinho.git
# ref: main
Após editar o pubspec.yaml, execute flutter pub get (ou dart pub get).
⚡ Guia Rápido de Inicialização e Uso
1. Inicialização no main.dart
Configure o Loguinho no ponto de entrada da sua aplicação de acordo com o ambiente:
import 'package:flutter/material.dart';
import 'package:loguinho/loguinho.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
// Configura para ambiente de desenvolvimento (ANSI colorido no console)
Loguinho.configure(LoggerConfig.development());
// Em produção, basta alternar para:
// Loguinho.configure(LoggerConfig.production());
// (Opcional) Associe a sessão e usuário logado para correlação de logs
Loguinho.setSessionId('sess_987654321');
Loguinho.setUserId('usuario@empresa.com');
runApp(const MyApp());
}
2. Registrando Logs na Aplicação
O Loguinho oferece métodos semânticos para cada tipo de evento:
import 'package:loguinho/loguinho.dart';
// Logs informativos e depuração
Loguinho.debug('Inicializando módulo de pagamentos...');
Loguinho.info('Navegador de checkout aberto');
Loguinho.success('Compra realizada com sucesso!');
// Logs com exceções e erros
try {
// operação de rede
} catch (e, stackTrace) {
Loguinho.error(
'Falha ao conectar com o gateway de pagamento',
category: 'PAYMENT',
error: e,
attributes: {'retryCount': 3},
);
}
// Logs especializados
Loguinho.network('POST /v1/checkout 200 OK', attributes: {'responseTimeMs': 145});
Loguinho.security('Tentativa de acesso a recurso restrito', category: 'AUTH');
Loguinho.performance('Tempo de carregamento da tela', attributes: {'durationMs': 82});
// Page Logs (Registro de Visualização de Páginas/Telas)
Loguinho.page('HomePage', attributes: {'tab': 'overview'});
Loguinho.page('ProductDetailsPage', attributes: {'productId': 'prod_9982'});
3. Registro Automático de Navegação e Rotas no Flutter
Você pode capturar a navegação de rotas automaticamente no seu MaterialApp utilizando o LoguinhoNavigatorObserver:
MaterialApp(
title: 'Meu App',
navigatorObservers: [
LoguinhoNavigatorObserver(), // Captura automaticamente didPush, didPop e didReplace
],
builder: (context, child) => LoguinhoOverlay(child: child), // (Opcional) Adiciona o botão flutuante 🪵
home: const HomePage(),
);
🛡️ Mascaramento Automático de Dados Sensíveis (PII)
Por padrão no perfil de produção (ou ativando a opção no sanitizer), o Loguinho higieniza automaticamente mensagens e atributos:
Loguinho.info(
'Autenticando cliente com CPF 123.456.789-00',
attributes: {
'email': 'cliente@empresa.com',
'password': 'MinhaSenhaSecreta123',
'cardNumber': '4532 1178 9012 3456',
},
);
Saída Estruturada Sanitizada:
{
"timestamp": "2026-07-31T12:00:00.000Z",
"level": "INFO",
"message": "Autenticando cliente com CPF ***.***.***-**",
"attributes": {
"email": "c***e@empresa.com",
"password": "[MASCARADO_SEGURANCA]",
"cardNumber": "**** **** **** 3456"
},
"sessionId": "sess_987654321"
}
🏗️ Boas Práticas: Clean Architecture e Inversão de Dependência (DIP)
Para não acoplar seu código de negócio diretamente à biblioteca de log e facilitar testes unitários, recomendamos criar uma abstração da camada de infraestrutura usando o Adapter Pattern:
1. Crie uma Interface no seu Projeto (domain/services/i_logger.dart)
abstract class ILogger {
void debug(String message, {String? category, Map<String, dynamic>? attributes});
void info(String message, {String? category, Map<String, dynamic>? attributes});
void error(String message, {String? category, Map<String, dynamic>? attributes, Object? error});
}
2. Crie o Adapter Concreto (infrastructure/logging/loguinho_logger_adapter.dart)
import 'package:loguinho/loguinho.dart';
import 'package:meu_app/domain/services/i_logger.dart';
class LoguinhoLoggerAdapter implements ILogger {
@override
void debug(String message, {String? category, Map<String, dynamic>? attributes}) {
Loguinho.debug(message, category: category, attributes: attributes);
}
@override
void info(String message, {String? category, Map<String, dynamic>? attributes}) {
Loguinho.info(message, category: category, attributes: attributes);
}
@override
void error(String message, {String? category, Map<String, dynamic>? attributes, Object? error}) {
Loguinho.error(message, category: category, attributes: attributes, error: error);
}
}
3. Injete o Logger na sua Classe de Negócio (Bloc/Controller/Service)
class PaymentController {
final ILogger _logger;
PaymentController(this._logger);
Future<void> processPayment(double amount) async {
_logger.info('Iniciando processamento', attributes: {'amount': amount});
// lógica de negócio...
}
}
🧪 Como Testar Seu Código e o Pacote
1. Testando Classes de Negócio do Seu App (Com Mock ou Fake Logger)
Como a sua classe de negócio depende da interface ILogger, nos testes unitários do seu app você pode passar uma implementação Fake:
import 'package:flutter_test/flutter_test.dart';
import 'package:meu_app/domain/services/i_logger.dart';
import 'package:meu_app/controllers/payment_controller.dart';
class FakeLogger implements ILogger {
final List<String> logs = [];
@override
void debug(String message, {String? category, Map<String, dynamic>? attributes}) => logs.add(message);
@override
void info(String message, {String? category, Map<String, dynamic>? attributes}) => logs.add(message);
@override
void error(String message, {String? category, Map<String, dynamic>? attributes, Object? error}) => logs.add(message);
}
void main() {
test('Deve registrar log ao processar pagamento', () async {
final fakeLogger = FakeLogger();
final controller = PaymentController(fakeLogger);
await controller.processPayment(150.0);
expect(fakeLogger.logs, contains('Iniciando processamento'));
});
}
2. Testando com o Buffer em Memória do próprio Loguinho
Se preferir assertar os eventos gravados no buffer do Loguinho durante um teste de integração:
test('Deve validar buffer de memória do Loguinho', () {
Loguinho.configure(LoggerConfig.development());
Loguinho.info('Evento de Teste');
final bufferedLogs = Loguinho.memoryBuffer.getEvents();
expect(bufferedLogs.any((e) => e.message == 'Evento de Teste'), isTrue);
});
3. Rodando os Testes da própria Biblioteca Loguinho
Caso queira contribuir ou validar a biblioteca localmente:
# Clone o repositório:
git clone https://github.com/flubit-dev/loguinho.git
cd loguinho
# Execute a suíte de testes unitários:
dart test
📄 Documentação Técnica Detalhada (doc/)
Para aprofundamento arquitetural e especificações técnicas completas, consulte o diretório doc/:
- 📘 Master Specification (
doc/README.md): Visão geral do problema, requisitos funcionais e não-funcionais. - 📊 Benchmark & Estudo de Mercado (
doc/BENCHMARK_AND_MARKET_RESEARCH.md): Comparativo técnico comlogger,talker,TimbereZap. - 🏛️ Arquitetura, Segurança e Observabilidade (
doc/ARCHITECTURE_AND_SECURITY.md): Princípios SOLID, algoritmo PII Sanitizer e W3C OpenTelemetry. - ⚡ Persistência, Performance e Roadmap (
doc/PERSISTENCE_AND_PERFORMANCE.md): Buffer circular offline, zero-FPS impact e plano evolutivo.
📜 Licença
Este repositório está sob a licença MIT. Veja o arquivo LICENSE para mais detalhes.