risetechapps / monitoring-for-laravel
Package info
github.com/risetechapps/monitoring-for-laravel
pkg:composer/risetechapps/monitoring-for-laravel
Requires
- php: ^8.3
- aws/aws-sdk-php: ^3.363
- hisorange/browser-detect: ^4.5
- illuminate/support: ^12.0
- laravel/sanctum: ^4.0
- risetechapps/risetools: ^2.0.0
Requires (Dev)
- orchestra/testbench: ^9.0
- phpunit/phpunit: ^11.0
README
Monitoring for Laravel é um pacote de monitoramento completo para aplicações Laravel, desenvolvido pela RiseTechApps. Ele captura automaticamente eventos da aplicação — requisições HTTP, exceções, jobs, comandos, notificações, e-mails, gates de autorização, eventos e muito mais — com suporte a múltiplos drivers de armazenamento.
Requisitos
- PHP
^8.3 - Laravel
^12.0 - Laravel Sanctum
^4.0
Instalação
Instale o pacote via Composer:
composer require risetechapps/monitoring-for-laravel
O pacote se registra automaticamente via auto-discovery do Laravel. O ServiceProvider e o alias Logs são configurados automaticamente.
Publicar a configuração
php artisan vendor:publish --tag=config --provider="RiseTechApps\Monitoring\MonitoringServiceProvider"
Isso criará o arquivo config/monitoring.php na sua aplicação.
Executar as migrações (drivers MySQL / PostgreSQL)
php artisan migrate
As migrações criam:
- A tabela
monitoringcom os campos padrão - Índices para otimização de consultas
- Campos de resolução de exceções (
resolved_at,resolved_by) — úteis para marcar exceções como "resolvidas"
Configuração
O arquivo config/monitoring.php centraliza todas as opções do pacote.
Opções principais
return [ // Habilita ou desabilita o monitoramento globalmente 'enabled' => env('MONITORING_ENABLED', true), // Driver de armazenamento: 'single' ou 'database' 'driver' => env('MONITORING_DRIVER', 'single'), // Quantidade de entradas acumuladas antes de persistir (buffer) 'buffer_size' => (int) env('MONITORING_BUFFER_SIZE', 5), 'watchers' => [ ... ], 'drivers' => [ ... ], ];
Variáveis de ambiente
| Variável | Padrão | Descrição |
|---|---|---|
MONITORING_ENABLED |
true |
Liga/desliga o monitoramento |
MONITORING_DRIVER |
single |
Driver de armazenamento |
Drivers de Armazenamento
O pacote suporta quatro drivers, configuráveis via MONITORING_DRIVER.
single — Arquivo de Log
Persiste os eventos em um arquivo local (storage/logs/monitoring.log). Ideal para desenvolvimento ou ambientes sem banco de dados.
MONITORING_DRIVER=single
mysql — MySQL
Armazena os eventos na tabela monitoring de uma conexão MySQL.
MONITORING_DRIVER=mysql DB_CONNECTION=mysql
// config/monitoring.php 'mysql' => [ 'connection' => env('DB_CONNECTION', 'mysql'), ],
pgsql — PostgreSQL
Idêntico ao driver MySQL, mas para conexões PostgreSQL.
MONITORING_DRIVER=pgsql DB_CONNECTION=pgsql
'pgsql' => [ 'connection' => env('DB_CONNECTION', 'pgsql'), ],
Watchers
Os watchers são os componentes responsáveis por interceptar e registrar cada categoria de evento. Todos podem ser habilitados/desabilitados individualmente no arquivo de configuração.
RequestWatcher — Requisições HTTP
Monitora todas as requisições HTTP recebidas pela aplicação.
Dados coletados: IP do cliente, URI, método HTTP, controller/action, middlewares, headers, payload, sessão, resposta, duração (ms) e uso de memória (MB).
Opções de filtro:
\RiseTechApps\Monitoring\Watchers\RequestWatcher::class => [ 'enabled' => true, 'options' => [ 'ignore_http_methods' => ['options'], // Ignora métodos HTTP específicos 'ignore_status_codes' => [404], // Ignora códigos de status HTTP 'ignore_paths' => ['telescope', 'horizon'], // Ignora paths específicos 'size_limit' => 64, // Limite de tamanho da resposta em KB ], ],
Segurança: Os campos
password,password_confirmation,authorizationephp-auth-pwsão automaticamente mascarados como********.
ExceptionWatcher — Exceções
Captura exceções registradas via Log::error(), Log::critical() e similares que passem uma instância de Throwable no contexto.
Dados coletados: classe da exceção, arquivo, linha, mensagem, contexto adicional, stack trace e preview de código (linhas ao redor da exceção).
Opções:
\RiseTechApps\Monitoring\Watchers\ExceptionWatcher::class => [ 'enabled' => true, 'options' => [ // Ignorar classes de exceção específicas 'ignore_exceptions' => [ \Illuminate\Validation\ValidationException::class, \Symfony\Component\HttpKernel\Exception\NotFoundHttpException::class, ], // Ignorar exceções cujas mensagens contenham estes textos 'ignore_messages_containing' => ['password', 'sensitive_data'], // Ignorar exceções de arquivos que contenham estes caminhos 'ignore_files_containing' => ['/vendor/'], ], ],
EventWatcher — Eventos
Registra os eventos disparados na aplicação, excluindo eventos internos do framework por padrão.
Dados coletados: nome do evento, payload formatado, lista de listeners e indicação se o evento é broadcast.
Opções:
\RiseTechApps\Monitoring\Watchers\EventWatcher::class => [ 'enabled' => true, 'options' => [ 'ignore' => [ 'App\Events\MeuEventoInterno', ], ], ],
CommandWatcher — Artisan Commands
Monitora comandos Artisan executados.
Dados coletados: nome do comando, código de saída (exit_code), argumentos e opções.
Os comandos
schedule:run,schedule:finish,package:discover,horizon:*,migrate:*e outros comandos internos são ignorados automaticamente.
Opções:
\RiseTechApps\Monitoring\Watchers\CommandWatcher::class => [ 'enabled' => true, 'options' => [ 'ignore' => ['meu:comando-interno'], ], ],
ScheduleWatcher — Tarefas Agendadas
Registra a execução das tarefas agendadas do Laravel Scheduler.
Dados coletados: comando ou closure, descrição, expressão cron, timezone, usuário e saída do comando.
Opções:
\RiseTechApps\Monitoring\Watchers\ScheduleWatcher::class => [ 'enabled' => true, 'options' => [ // Ignorar comandos agendados específicos 'ignore_commands' => ['my:scheduled-command'], // Ignorar closures (tarefas agendadas como closures) 'ignore_closures' => false, ], ],
JobWatcher — Jobs de Fila
Monitora o ciclo de vida completo de jobs, incluindo pendente, processado e falho.
Dados coletados:
- Pendente: nome, conexão, fila, tentativas, timeout, payload,
batch_id - Processado: status, nome do job, tentativas, hostname
- Falho: status, nome do job, mensagem de exceção, trace, preview de código, hostname
Opções:
\RiseTechApps\Monitoring\Watchers\JobWatcher::class => [ 'enabled' => true, 'options' => [ // Ignorar namespaces de jobs 'ignore_namespaces' => [ 'App\Jobs\Internal\', ], // Ignorar jobs específicos 'ignore_jobs' => [ \App\Jobs\HeavyLoggingJob::class, ], ], ],
Jobs do próprio pacote, Telescope, Horizon e Pulse são ignorados automaticamente.
QueueWatcher — Worker de Fila
Detecta parada e retomada do worker de fila. Cria um arquivo storage/framework/queue_stopping ao parar e o remove ao retomar.
GateWatcher — Autorização
Monitora todas as verificações de autorização (Gates e Policies).
Dados coletados: ability verificada, resultado (allowed/denied), argumentos e arquivo/linha de origem da chamada.
Opções:
\RiseTechApps\Monitoring\Watchers\GateWatcher::class => [ 'enabled' => true, 'options' => [ 'ignore_abilities' => ['viewNova'], ], ],
NotificationWatcher — Notificações
Captura notificações enviadas pela aplicação.
Dados coletados: classe da notificação, se é queued, notifiable, canal, resposta e UUID da notificação.
Opções:
\RiseTechApps\Monitoring\Watchers\NotificationWatcher::class => [ 'enabled' => true, 'options' => [ // Ignorar classes de notificação específicas 'ignore_notifications' => [ \App\Notifications\TestNotification::class, ], // Ignorar canais específicos 'ignore_channels' => ['broadcast', 'slack'], // Ignorar notificações anônimas (AnonymousNotifiable) 'ignore_anonymous' => false, ], ],
MailWatcher — E-mails
Registra todos os e-mails enviados.
Dados coletados: classe mailable, se é queued, remetente, reply-to, destinatários (to, cc, bcc), assunto, corpo HTML e e-mail bruto.
Opções:
\RiseTechApps\Monitoring\Watchers\MailWatcher::class => [ 'enabled' => true, 'options' => [ // Ignorar classes Mailable específicas 'ignore_mailables' => [ \App\Mail\TestMail::class, ], // Ignorar e-mails cujo assunto contenha estes textos 'ignore_subjects_containing' => ['[Test]', '[Local]'], // Ignorar e-mails de remetentes específicos 'ignore_from_addresses' => ['noreply@example.com'], // Ignorar e-mails para destinatários específicos 'ignore_to_addresses' => ['test@example.com'], ], ],
ClientRequestWatcher — HTTP Client (Saída)
Monitora requisições HTTP feitas pela aplicação usando o Http:: facade do Laravel.
Dados coletados: método, URI, headers, payload, status da resposta, headers da resposta, corpo da resposta e duração (ms).
Requisições para os hosts da própria plataforma de monitoramento são ignoradas automaticamente para evitar loops.
Opções:
\RiseTechApps\Monitoring\Watchers\ClientRequestWatcher::class => [ 'enabled' => true, 'options' => [ 'ignore_hosts' => ['api.interna.com'], 'size_limit' => 64, ], ], --- ### QueryWatcher — Queries Lentas Monitora automaticamente queries SQL que excedem um tempo limite configurado. **Dados coletados:** SQL completo, bindings, tempo de execução, conexão utilizada, arquivo e linha de origem. **Opções:** ```php \RiseTechApps\Monitoring\Watchers\QueryWatcher::class => [ 'enabled' => true, 'options' => [ // Threshold em ms para considerar query lenta 'slow_query_threshold_ms' => 100, // Padrões de SQL que devem ser ignorados 'ignore_patterns' => ['information_schema', 'migrations', 'telescope'], // Logar bindings das queries 'log_bindings' => true, // Tamanho máximo do SQL antes de truncar 'max_sql_length' => 5000, ], ],
Exemplo de uso:
# Ver queries lentas GET /monitoring/type/query # Buscar queries específicas GET /monitoring/search?q=SELECT * FROM orders
CacheWatcher — Operações de Cache
Monitora hits, misses, escritas e deleções no cache da aplicação.
Dados coletados: operação (hit/miss/write/delete), key, store (redis/memcached/file), TTL (para writes).
Opções:
\RiseTechApps\Monitoring\Watchers\CacheWatcher::class => [ 'enabled' => true, 'options' => [ // Registrar cache hits 'track_hits' => true, // Registrar cache misses 'track_misses' => true, // Chaves de cache que devem ser ignoradas 'ignore_keys' => ['config', 'routes', 'telescope'], ], ],
Casos de uso:
- Identificar keys com baixo hit rate
- Detectar cache thrashing (misses excessivos)
- Analisar TTL efetivo das keys
---
## Loggly — Logger Estruturado
O `Loggly` é o componente de log manual do pacote, acessível via função helper global. Ele oferece uma API fluente para registrar logs ricos e estruturados.
### Helpers disponíveis
```php
loggly() // Info (padrão)
logglyInfo() // Nível INFO
logglyDebug() // Nível DEBUG
logglyWarning() // Nível WARNING
logglyNotice() // Nível NOTICE
logglyError() // Nível ERROR
logglyCritical() // Nível CRITICAL
logglyAlert() // Nível ALERT
logglyEmergency() // Nível EMERGENCY
logglyModel() // Nível MODEL
API fluente
loggly() ->level('error') // Define o nível ->performedOn($user) // Modelo ou string do contexto ->exception($exception) // Captura dados da exceção ->withProperties(['key' => 'value']) // Propriedades extras ->withContext(['request_id' => '123']) // Contexto adicional ->withTags(['pagamento', 'critico']) // Tags para categorização ->withRequest($request->all()) // Dados da requisição ->withResponse($response->json()) // Dados da resposta ->at(new DateTime()) // Timestamp personalizado ->encrypt() // Encripta a mensagem ->to('loggly') // Destino: 'loggly' ou 'file' ->log('Mensagem do log');
Exemplos de uso
Log simples:
logglyInfo()->log('Usuário autenticado com sucesso.');
Log de exceção com contexto:
try { // ... } catch (Exception $e) { logglyError() ->performedOn(PaymentService::class) ->exception($e) ->withProperties(['order_id' => $orderId]) ->log('Falha ao processar pagamento.'); }
Log de modelo:
logglyModel() ->performedOn($produto) ->withContext(['acao' => 'preco_atualizado']) ->log('Preço do produto foi alterado.');
Salvar em arquivo (sem enviar para o driver principal):
loggly()->to('file')->log('Debug local.');
Trait HasLoggly — Auditoria de Models
Adicione a trait HasLoggly a qualquer Model Eloquent para registrar automaticamente as operações de criação, atualização, exclusão e restauração.
use RiseTechApps\Monitoring\Traits\HasLoggly\HasLoggly; class Produto extends Model { use HasLoggly; }
Eventos monitorados
| Evento Eloquent | Ação registrada |
|---|---|
created |
Created record. |
updated |
Updated record. (com diff dos campos alterados) |
deleted |
Deleted record. ou Force deleted record. |
restored |
Restored record. (apenas com SoftDeletes) |
Dados coletados
- updated: classe do model, valores antigos, valores novos e um diff com
old/newpara cada campo alterado. - created/deleted/restored: classe do model e atributos atuais do model.
Se o Model usar
SoftDeletes, o eventorestoredé monitorado automaticamente.
Métricas Customizáveis
Além dos watchers automáticos, você pode registrar métricas de negócio personalizadas usando o helper monitoring().
Tipos de Métricas
Gauge (Valor Pontual)
Registra um valor em um momento específico. Ideal para contagens, estados ou níveis.
// Contagem de pedidos pendentes monitoring()->gauge('pedidos_pendentes', Pedido::where('status', 'pendente')->count()); // Valor em estoque de um produto monitoring()->gauge('estoque_produto', $produto->quantidade, ['produto_id' => $produto->id]); // Usuários ativos no momento monitoring()->gauge('usuarios_ativos', Cache::get('online_users', 0));
Counter (Contador)
Incrementa um contador. Ideal para eventos discretos.
// Checkout concluído monitoring()->increment('checkout_concluido'); // Incremento com valor personalizado monitoring()->increment('itens_vendidos', $quantidade); // Com tags adicionais monitoring()->increment('pagamentos', 1, ['metodo' => 'cartao']); monitoring()->increment('pagamentos', 1, ['metodo' => 'boleto']);
Histogram (Distribuição)
Registra valores em uma distribuição. Ideal para tempos e tamanhos.
// Tempo de processamento em milissegundos monitoring()->histogram('tempo_processamento', 250); // Tamanho da resposta da API monitoring()->histogram('tamanho_resposta_api', strlen($responseBody)); // Com tags para segmentação monitoring()->histogram('tempo_db', $queryTime, ['tabela' => 'pedidos']);
Timer (Medidor de Tempo)
Executa um código e automaticamente registra o tempo de execução.
// Medir tempo de uma operação $resultado = monitoring()->timer('processar_pedido', function() use ($pedido) { return $this->processarPedido($pedido); }); // Medir chamada de API externa $dados = monitoring()->timer('api_pagamento', function() use ($payload) { return Http::post('https://api.pagamento.com', $payload)->json(); }); // Com tags $relatorio = monitoring()->timer('gerar_relatorio', function() { return $this->gerarRelatorioVendas(); }, ['tipo' => 'vendas', 'periodo' => 'mensal']);
Dados Coletados
Cada métrica registra:
| Campo | Descrição |
|---|---|
metric_type |
Tipo: gauge, counter, histogram |
metric_name |
Nome da métrica (ex: checkout_concluido) |
value |
Valor numérico registrado |
tags |
Tags adicionais para segmentação |
created_at |
Timestamp do registro |
Exemplos de Uso na Prática
Controller de Checkout:
class CheckoutController extends Controller { public function processar(Request $request) { $resultado = monitoring()->timer('checkout_total', function() use ($request) { // Validação $dados = $request->validate([...]); // Processamento do pagamento $pagamento = monitoring()->timer('processar_pagamento', function() use ($dados) { return $this->pagamentoService->processar($dados); }, ['gateway' => $dados['gateway']]); // Criar pedido $pedido = Pedido::create([...]); // Atualizar estoque monitoring()->gauge('estoque_reduzido', $this->atualizarEstoque($pedido)); return $pedido; }); monitoring()->increment('pedidos_criados', 1, [ 'metodo_pagamento' => $resultado->metodo ]); return response()->json($resultado); } }
Job de Processamento:
class ProcessarImportacaoJob implements ShouldQueue { public function handle() { monitoring()->gauge('registros_a_processar', $this->totalRegistros); foreach ($this->registros as $registro) { $processado = monitoring()->timer('processar_registro', function() use ($registro) { return $this->processar($registro); }); if ($processado) { monitoring()->increment('registros_sucesso'); } else { monitoring()->increment('registros_falha'); } } monitoring()->gauge('registros_restantes', 0); } }
Comando Artisan:
class LimparCacheCommand extends Command { public function handle() { $chavesRemovidas = monitoring()->timer('limpar_cache', function() { return Cache::flush(); }); monitoring()->increment('cache_limpo', $chavesRemovidas); monitoring()->gauge('cache_tamanho', Cache::getMemoryUsage()); $this->info("Cache limpo: {$chavesRemovidas} chaves removidas."); } }
Consultando Métricas
As métricas são registradas com type = 'metric' e podem ser consultadas via API ou repositório:
use RiseTechApps\Monitoring\Entry\EntryType; // Todas as métricas $metricas = $monitoring->getEventsByTypes(EntryType::METRIC); // Filtrar por nome de métrica $checkouts = $metricas->filter(fn($m) => $m['content']['metric_name'] === 'checkout_concluido'); // Calcular estatísticas $totalCheckouts = $checkouts->sum('content.value'); $tempoMedio = $checkouts->where('content.metric_type', 'histogram')->avg('content.value');
Middleware monitoring.disable
Use o middleware para desabilitar o monitoramento em rotas específicas, como painéis administrativos ou endpoints de health check.
Registrando nas rotas
// routes/web.php ou routes/api.php Route::middleware('monitoring.disable')->group(function () { Route::get('/health', fn () => response()->json(['status' => 'ok'])); Route::get('/admin/dashboard', [AdminController::class, 'index']); });
Aplicando em um controller
public function __construct() { $this->middleware('monitoring.disable'); }
Controle Programático
Desabilitar o monitoramento
use RiseTechApps\Monitoring\Monitoring; Monitoring::disable();
Verificar se está habilitado
if (Monitoring::isEnabled()) { // ... }
Adicionar tags globais a todas as entradas
// Em um ServiceProvider Monitoring::tag(function ($entry) { return ['ambiente:' . app()->environment()]; });
Ocultar parâmetros sensíveis
// Em um ServiceProvider Monitoring::$hiddenRequestParameters = ['cartao_numero', 'cvv']; Monitoring::$hiddenResponseParameters = ['token_acesso', 'secret'];
Registrar rotas do pacote
Monitoring::routes();
Estrutura da Tabela (monitoring)
Quando usando os drivers mysql ou pgsql, os eventos são armazenados na tabela monitoring:
| Coluna | Tipo | Descrição |
|---|---|---|
id |
UUID (PK) | Identificador primário |
uuid |
UUID (unique) | Identificador único da entrada |
batch_id |
UUID | Agrupa entradas de uma mesma requisição/job |
type |
string(20) | Tipo da entrada (veja abaixo) |
content |
JSON | Dados específicos do evento |
tags |
JSON | Tags associadas à entrada |
user |
JSON | Dados do usuário autenticado |
device |
JSON | Dados do dispositivo/browser |
resolved_at |
timestamp (nullable) | Quando a exceção foi marcada como resolvida |
resolved_by |
string (nullable) | Identificador de quem resolveu (email/user_id) |
created_at |
timestamp | — |
updated_at |
timestamp | — |
Tipos de entrada (type)
| Constante | Valor | Descrição |
|---|---|---|
EntryType::REQUEST |
request |
Requisição HTTP recebida |
EntryType::EXCEPTION |
exception |
Exceção capturada |
EntryType::EVENT |
event |
Evento da aplicação |
EntryType::COMMAND |
command |
Comando Artisan |
EntryType::SCHEDULED_TASK |
schedule |
Tarefa agendada |
EntryType::JOB |
job |
Job de fila |
EntryType::GATE |
gate |
Verificação de autorização |
EntryType::NOTIFICATION |
notification |
Notificação enviada |
EntryType::MAIL |
mail |
E-mail enviado |
EntryType::CLIENT_REQUEST |
client_request |
Requisição HTTP de saída |
EntryType::LOG |
log |
Log manual via Loggly |
EntryType::MODEL |
model |
Operação em Model Eloquent |
EntryType::QUERY |
query |
Query no banco de dados |
EntryType::METRIC |
metric |
Métrica de negócio customizada |
Buffer de Entradas
O pacote utiliza um buffer em memória para otimizar a performance, evitando uma escrita no storage para cada evento individualmente.
- As entradas são acumuladas no buffer até atingir
buffer_size(padrão:5). - O buffer é descarregado automaticamente ao final de cada requisição HTTP (evento
RequestHandled). - Em ambientes de console (jobs, commands), o buffer é descarregado imediatamente após cada entrada.
Configure o tamanho do buffer:
MONITORING_BUFFER_SIZE=10
Consultando os Registros de Monitoramento
O pacote fornece um repositório com métodos padronizados para leitura dos eventos, disponíveis para os drivers dabase. O driver single (arquivo) não suporta leitura — seus métodos retornam coleções vazias.
Injetando o Repositório
Você pode injetar o MonitoringRepositoryInterface em qualquer controller, service ou job:
use RiseTechApps\Monitoring\Repository\Contracts\MonitoringRepositoryInterface; class MonitoringDashboardController extends Controller { public function __construct( protected MonitoringRepositoryInterface $monitoring ) {} }
Ou resolver diretamente via container:
$monitoring = app(MonitoringRepositoryInterface::class);
Métodos de Consulta
Todos os métodos retornam uma Illuminate\Support\Collection.
Todos os eventos
$events = $monitoring->getAllEvents(); // Retorna todos os registros ordenados por created_at DESC
Evento por ID
Retorna o evento específico e todos os eventos relacionados do mesmo batch_id no campo related_events.
$event = $monitoring->getEventById('uuid-ou-id-aqui'); // Estrutura de retorno: // [ // 'id' => '...', // 'uuid' => '...', // 'batch_id' => '...', // 'type' => 'request', // 'content' => [...], // 'tags' => [...], // 'user' => [...], // 'device' => [...], // 'created_at' => '...', // 'updated_at' => '...', // 'related_events' => [...], // outros eventos do mesmo batch // ]
Eventos por tipo
Filtra por um dos tipos definidos em EntryType. Retorna cada evento com seu related_events.
use RiseTechApps\Monitoring\Entry\EntryType; $requests = $monitoring->getEventsByTypes(EntryType::REQUEST); $exceptions = $monitoring->getEventsByTypes(EntryType::EXCEPTION); $jobs = $monitoring->getEventsByTypes(EntryType::JOB); $commands = $monitoring->getEventsByTypes(EntryType::COMMAND); $mails = $monitoring->getEventsByTypes(EntryType::MAIL); $logs = $monitoring->getEventsByTypes(EntryType::LOG); $models = $monitoring->getEventsByTypes(EntryType::MODEL); $gates = $monitoring->getEventsByTypes(EntryType::GATE); $events = $monitoring->getEventsByTypes(EntryType::EVENT); $schedules = $monitoring->getEventsByTypes(EntryType::SCHEDULED_TASK); $notifs = $monitoring->getEventsByTypes(EntryType::NOTIFICATION); $outbound = $monitoring->getEventsByTypes(EntryType::CLIENT_REQUEST);
Eventos por batch
Retorna todos os eventos que pertencem a um mesmo ciclo de requisição ou job, agrupados pelo batch_id.
$batchEvents = $monitoring->getByBatch('batch-uuid-aqui');
Lista de tipos disponíveis
$types = $monitoring->getEventsByTags(); // Retorna: ['command', 'event', 'exception', 'job', 'log', 'mail', // 'model', 'notification', 'query', 'request', // 'schedule', 'client_request', 'gate']
Consulta por Período
Filtra eventos pelos períodos pré-definidos:
$monitoring->getLast24Hours(); // Últimas 24 horas $monitoring->getLast7Days(); // Últimos 7 dias $monitoring->getLast15Days(); // Últimos 15 dias $monitoring->getLast30Days(); // Últimos 30 dias $monitoring->getLast60Days(); // Últimos 60 dias $monitoring->getLast90Days(); // Últimos 90 dias
Suporte por Driver
| Método | database |
single |
|---|---|---|
getAllEvents() |
✅ | ❌ |
getEventById() |
✅ | ❌ |
getEventsByTypes() |
✅ | ❌ |
getEventsByTags() |
✅ | ✅* |
getByBatch() |
✅ | ❌ |
getTimelineByTag() |
✅ | ❌ |
gauge() |
✅ | ✅ |
increment() |
✅ | ✅ |
histogram() |
✅ | ✅ |
timer() |
✅ | ✅ |
getLast24Hours() |
✅ | ❌ |
getLast7Days() |
✅ | ❌ |
getLast15Days() |
✅ | ❌ |
getLast30Days() |
✅ | ❌ |
getLast60Days() |
✅ | ❌ |
getLast90Days() |
✅ | ❌ |
resolveEvent() |
✅ | ❌ |
resolveExceptionType() |
✅ | ❌ |
unresolveEvent() |
✅ | ❌ |
getUnresolvedExceptions() |
✅ | ❌ |
*
getEventsByTags()no driversingleretorna apenas a lista de tipos disponíveis.
Rotas HTTP de Consulta
O pacote disponibiliza rotas prontas para expor os eventos via API. Registre-as no AppServiceProvider ou RouteServiceProvider:
use RiseTechApps\Monitoring\Monitoring; // Registro básico (usa middleware 'api' por padrão) Monitoring::routes();
Opções disponíveis:
Monitoring::routes([ 'middleware' => ['api', 'auth:sanctum'], // middlewares customizados 'authorize' => 'view-monitoring', // Gate/Policy de autorização 'rate_limit' => '60,1', // throttle: 60 req/min 'as' => 'monitoring.', // prefixo dos nomes das rotas ]);
Endpoints registrados:
| Método | URI | Nome | Descrição |
|---|---|---|---|
GET |
/monitoring |
monitoring.index |
Lista todos os eventos |
GET |
/monitoring/{id} |
monitoring.show |
Detalhe de um evento + relacionados |
GET |
/monitoring/type/{type} |
monitoring.type |
Filtra por tipo |
POST |
/monitoring/tags |
monitoring.tags |
Lista tipos disponíveis |
GET |
/monitoring/timeline/{tag}/{value} |
monitoring.timeline |
Timeline cronológico por tag |
Rotas de Health Check:
| Método | URI | Nome | Descrição |
|---|---|---|---|
GET |
/monitoring/health |
monitoring.health |
Verifica saúde da aplicação (DB, Cache, Queue, Storage) |
Rotas de Busca e Comparação:
| Método | URI | Nome | Descrição |
|---|---|---|---|
GET |
/monitoring/search |
monitoring.search |
Busca full-text nos eventos |
GET |
/monitoring/compare |
monitoring.compare |
Compara métricas entre dois períodos |
Rotas de Resolução de Exceções:
| Método | URI | Nome | Descrição |
|---|---|---|---|
GET |
/monitoring/exceptions/unresolved |
monitoring.exceptions.unresolved |
Lista exceções não resolvidas agrupadas por tipo |
POST |
/monitoring/resolve-exception |
monitoring.exceptions.resolve-type |
Marca todas as exceções de um tipo como resolvidas |
POST |
/monitoring/{id}/resolve |
monitoring.resolve |
Marca um evento específico como resolvido |
POST |
/monitoring/{id}/unresolve |
monitoring.unresolve |
Remove o status de resolvido de um evento |
As rotas do painel de monitoramento usam automaticamente o middleware
monitoring.disablepara não serem monitoradas.
Timeline por Tag
Visualize o fluxo completo de eventos relacionados a uma tag específica em ordem cronológica. Útil para rastrear o ciclo de vida de um pedido, usuário, ou qualquer entidade monitorada.
Endpoint
GET /monitoring/timeline/{tag}/{value}?period=24%20hours
Parâmetros:
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
tag |
string | Sim | Nome da tag (ex: pedido_id) |
value |
string | Sim | Valor da tag (ex: 123) |
period |
string | Não | Período de busca. Padrão: 24 hours. Opções: 1 hour, 6 hours, 12 hours, 24 hours, 7 days, 30 days, 90 days |
Exemplos de uso
Timeline de um pedido:
GET /monitoring/timeline/pedido_id/123?period=24%20hours
Timeline de um usuário específico:
GET /monitoring/timeline/user_id/550e8400-e29b-41d4-a716-446655440000?period=7%20days
Resposta
{
"tag": "pedido_id",
"value": "123",
"period": "24 hours",
"total_batches": 2,
"timeline": [
{
"batch_id": "abc-123-uuid",
"started_at": "2025-01-15 10:23:15",
"timeline": [
{
"id": "...",
"type": "request",
"type_label": "Requisição HTTP",
"icon": "🌐",
"content": { "method": "POST", "uri": "/api/pedidos", ... },
"tags": { "pedido_id": "123" },
"created_at": "2025-01-15 10:23:15"
},
{
"id": "...",
"type": "query",
"type_label": "Query SQL",
"icon": "🗄️",
"content": { "sql": "INSERT INTO pedidos...", "time_ms": 45 },
"tags": { "pedido_id": "123" },
"created_at": "2025-01-15 10:23:15"
},
{
"id": "...",
"type": "job",
"type_label": "Job",
"icon": "⚙️",
"content": { "displayName": "ProcessarPedidoJob", ... },
"tags": { "pedido_id": "123" },
"created_at": "2025-01-15 10:23:16"
},
{
"id": "...",
"type": "mail",
"type_label": "E-mail",
"icon": "📧",
"content": { "subject": "Pedido #123 recebido", ... },
"tags": { "pedido_id": "123" },
"created_at": "2025-01-15 10:23:18"
}
],
"duration_ms": 3000,
"event_count": 4
},
{
"batch_id": "def-456-uuid",
"started_at": "2025-01-15 14:45:22",
"timeline": [
{
"id": "...",
"type": "request",
"type_label": "Requisição HTTP",
"icon": "🌐",
"content": { "method": "PUT", "uri": "/api/pedidos/123", ... },
"tags": { "pedido_id": "123" },
"created_at": "2025-01-15 14:45:22"
},
{
"id": "...",
"type": "query",
"type_label": "Query SQL",
"icon": "🗄️",
"content": { "sql": "UPDATE pedidos...", "time_ms": 23 },
"tags": { "pedido_id": "123" },
"created_at": "2025-01-15 14:45:22"
}
],
"duration_ms": 800,
"event_count": 2
}
]
}
> **Nota:** Os eventos são agrupados por `batch_id` único. Se múltiplos eventos
> compartilharem o mesmo batch_id, você recebe apenas uma entrada na timeline
> contendo todos os eventos relacionados.
Uso programático
use RiseTechApps\Monitoring\Repository\Contracts\MonitoringRepositoryInterface; class PedidoController extends Controller { public function __construct( protected MonitoringRepositoryInterface $monitoring ) {} public function timeline(string $pedidoId) { // Busca todos os eventos relacionados ao pedido nas últimas 24h // Agrupados por batch_id único $timeline = $this->monitoring->getTimelineByTag('pedido_id', $pedidoId, '24 hours'); return response()->json([ 'pedido_id' => $pedidoId, 'total_operacoes' => $timeline->count(), 'operacoes' => $timeline->map(function ($batch) { return [ 'batch_id' => $batch['batch_id'], 'inicio' => $batch['started_at'], 'fim' => $batch['timeline']->last()['created_at'] ?? null, 'duracao_ms' => $batch['duration_ms'], 'eventos' => $batch['event_count'], 'passos' => $batch['timeline']->map(fn ($e) => [ 'hora' => $e['created_at'], 'tipo' => $e['type_label'], 'icone' => $e['icon'], ]), ]; }), ]); } }
Gerenciamento de Exceções Resolvidas
O pacote permite marcar exceções como "resolvidas", facilitando o acompanhamento de bugs e evitando poluição visual no dashboard.
Campos adicionais na resposta
Quando um evento é resolvido, os seguintes campos são adicionados à resposta:
[ 'id' => '...', 'uuid' => '...', 'type' => 'exception', 'content' => [...], // ... outros campos ... 'resolved_at' => '2025-01-15 14:30:00', // quando foi resolvido 'resolved_by' => 'user@example.com', // quem resolveu 'is_resolved' => true, // flag booleana ]
Listar exceções não resolvidas
GET /monitoring/exceptions/unresolved
Resposta:
[
{
"exception_class": "App\\Exceptions\\CustomException",
"count": 15,
"last_occurrence": "2025-01-15 10:23:00"
},
{
"exception_class": "Illuminate\\Validation\\ValidationException",
"count": 3,
"last_occurrence": "2025-01-15 09:45:00"
}
]
Marcar uma exceção como resolvida
POST /monitoring/{id}/resolve
Content-Type: application/json
{
"resolved_by": "user@example.com"
}
Marcar múltiplas exceções do mesmo tipo como resolvidas
POST /monitoring/resolve-exception
Content-Type: application/json
{
"exception_class": "App\\Exceptions\\CustomException",
"resolved_by": "user@example.com"
}
Resposta:
{
"message": "15 exceções marcadas como resolvidas.",
"exception_class": "App\\Exceptions\\CustomException",
"count": 15
}
Desfazer a resolução
POST /monitoring/{id}/unresolve
Uso programático
use RiseTechApps\Monitoring\Repository\Contracts\MonitoringRepositoryInterface; class ExceptionController extends Controller { public function __construct( protected MonitoringRepositoryInterface $monitoring ) {} // Marcar como resolvida public function resolve(string $id) { $success = $this->monitoring->resolveEvent( $id, auth()->user()?->email ); return $success ? response()->json(['message' => 'Resolvido!']) : response()->json(['message' => 'Não encontrado'], 404); } // Listar não resolvidas public function unresolved() { $exceptions = $this->monitoring->getUnresolvedExceptions(); return response()->json($exceptions); } }
Health Check
Endpoint para verificar a saúde da aplicação e suas dependências.
Endpoint
GET /monitoring/health
Resposta
{
"status": "healthy",
"checks": {
"database": { "status": "ok" },
"cache": { "status": "ok", "driver": "redis" },
"queue": { "status": "ok", "driver": "redis", "queue_size": 0 },
"storage": { "status": "ok", "disk": "local" }
},
"performance": {
"apdex_score": 0.94,
"throughput_per_minute": 245,
"error_rate_percent": 0.5
},
"timestamp": "2025-01-15T10:30:00Z"
}
Status possíveis
| Status | Significado |
|---|---|
healthy |
Todos os sistemas OK |
degraded |
Algum sistema com problemas leves |
unhealthy |
Falha crítica em algum sistema |
Uso em Load Balancers
# Health check para load balancer GET /monitoring/health # Retorna 200 se healthy/degraded # Retorna 503 se unhealthy
Sistema de Alertas
Configure notificações automáticas para eventos críticos via Slack, Discord ou Email.
Configuração
// config/monitoring.php 'alerts' => [ 'enabled' => env('MONITORING_ALERTS_ENABLED', true), // Webhooks 'slack_webhook' => env('MONITORING_SLACK_WEBHOOK'), 'discord_webhook' => env('MONITORING_DISCORD_WEBHOOK'), // Email 'email' => [ 'enabled' => true, 'to' => ['devops@empresa.com'], 'from' => 'monitoring@empresa.com', ], // Thresholds 'thresholds' => [ 'exceptions_per_minute' => 10, 'failed_jobs_per_hour' => 5, 'slow_request_ms' => 5000, 'slow_queries_per_minute' => 10, 'error_rate_percent' => 5.0, ], // Cooldown entre alertas (minutos) 'cooldown_minutes' => 5, ],
Variáveis de ambiente
MONITORING_ALERTS_ENABLED=true MONITORING_SLACK_WEBHOOK=https://hooks.slack.com/services/... MONITORING_DISCORD_WEBHOOK=https://discord.com/api/webhooks/... MONITORING_ALERTS_EMAIL_TO=devops@empresa.com,admin@empresa.com
Alertas Disparados
| Evento | Threshold | Mensagem |
|---|---|---|
| Exceção em produção | Qualquer | 🚨 Exceção: {class} - {message} |
| Requisição lenta | > 5000ms | ⏱️ Requisição lenta: {uri} - {duration}ms |
| Job falho | > 5/hora | 🔥 Job falhou: {job} |
| Query lenta | > 100ms | 🐢 Query lenta: {time}ms |
Cooldown
Para evitar spam, o mesmo tipo de alerta só é enviado a cada 5 minutos (configurável).
Relatórios Automáticos
Gere relatórios periódicos (diário, semanal, mensal) com métricas e estatísticas completas do sistema de monitoramento.
Configuração
// config/monitoring.php 'reports' => [ 'auto_schedule' => env('MONITORING_REPORTS_AUTO_SCHEDULE', false), 'timezone' => 'America/Sao_Paulo', 'daily' => [ 'enabled' => true, 'send_at' => '08:00', ], 'weekly' => [ 'enabled' => true, 'send_at' => '08:00', 'day' => 'monday', ], 'monthly' => [ 'enabled' => true, 'send_at' => '08:00', ], 'channels' => [ 'email' => [ 'enabled' => true, 'to' => ['devops@empresa.com'], 'from' => 'monitoring@empresa.com', ], 'slack' => ['enabled' => true], 'discord' => ['enabled' => true], ], ],
Variáveis de Ambiente
MONITORING_REPORTS_AUTO_SCHEDULE=true MONITORING_REPORT_EMAIL_TO=devops@empresa.com,admin@empresa.com MONITORING_REPORT_EMAIL_FROM=monitoring@empresa.com # Canais MONITORING_REPORT_EMAIL_ENABLED=true MONITORING_REPORT_SLACK_ENABLED=true MONITORING_REPORT_DISCORD_ENABLED=false
Comando Artisan
# Gerar relatório diário php artisan monitoring:report daily # Gerar e enviar automaticamente php artisan monitoring:report daily --send # Enviar para canais específicos php artisan monitoring:report weekly --send --channels=email,slack # Preview no console php artisan monitoring:report monthly --preview # Salvar HTML no storage php artisan monitoring:report daily --save
Conteúdo do Relatório
Cada relatório inclui:
1. Resumo Executivo
- Total de eventos
- Exceções, requisições, jobs
- Taxa de erro
- Tempo médio de resposta
2. Métricas de Performance
- Apdex Score
- Tempo mínimo, máximo e médio
- Queries lentas
3. Eventos por Tipo
- Distribuição percentual
- Gráficos de barras
4. Top Erros
- Exceções mais frequentes (não resolvidas)
- Contagem de ocorrências
5. Tendências
- Comparação com período anterior
- Indicadores de crescimento/queda
Agendamento Automático
Com MONITORING_REPORTS_AUTO_SCHEDULE=true:
| Relatório | Frequência | Horário |
|---|---|---|
| Diário | Todo dia | 08:00 |
| Semanal | Segundas-feiras | 08:00 |
| Mensal | Dia 1 de cada mês | 08:00 |
Relatórios Customizáveis (100% Autônomo)
O sistema de relatórios permite 100% de autonomia no envio. Você pode usar:
- Handlers Customizados - Substituir canais específicos ou todos
- Event Listener - Controle total via evento
ReportGenerated - Notificações Padrão - Email, Slack, Discord (funciona sem configuração extra)
Controle Total - Desabilitar Padrão
Para usar apenas suas notificações customizadas:
// Em um ServiceProvider use RiseTechApps\Monitoring\Services\Reporting\ReportService; public function boot(): void { // Desabilita notificações padrão ReportService::disableDefaultNotifications(); }
Handler Customizado para Relatórios
Implemente ReportHandlerInterface para criar seu próprio envio:
<?php namespace App\Monitoring\Handlers; use RiseTechApps\Monitoring\Contracts\ReportHandlerInterface; class MinhaNotificacaoEmail implements ReportHandlerInterface { public function send(array $report, string $html, array $config = []): bool { // Use sua própria lógica de envio return \Mail::send('minha-view-relatorio', [ 'relatorio' => $report, ], function ($message) use ($report, $config) { $message->to($config['to'] ?? 'admin@empresa.com') ->subject($report['period_label']); }); } public function isConfigured(array $config = []): bool { return !empty($config['to']); } public function getName(): string { return 'minha_notificacao_email'; } public function getSupportedChannels(): array { return ['email']; // Substitui só o email // return []; // Todos os canais // return ['email', 'slack']; // Email + Slack } }
Registre o handler:
use RiseTechApps\Monitoring\Services\Reporting\ReportService; use App\Monitoring\Handlers\MinhaNotificacaoEmail; public function boot(): void { // Substitui apenas o canal de email ReportService::registerHandler('meu_email', new MinhaNotificacaoEmail()); // Ou desabilita padrão e usa só o seu ReportService::disableDefaultNotifications(); }
Configure no config/monitoring.php:
'reports' => [ // ... outras configurações ... 'custom_handlers' => [ 'meu_email' => [ 'to' => 'admin@empresa.com', 'from' => 'monitoring@empresa.com', ], ], ],
Evento ReportGenerated
Ouça o evento para controle total:
<?php namespace App\Listeners; use RiseTechApps\Monitoring\Events\ReportGenerated; class EnviarMeuRelatorio { public function handle(ReportGenerated $event): void { // Acesso completo aos dados $period = $event->report['period']; // 'daily', 'weekly', 'monthly' $summary = $event->report['summary']; // Métricas $html = $event->html; // HTML renderizado $channels = $event->channels; // Canais solicitados // Envio customizado foreach ($channels as $channel) { match($channel) { 'email' => $this->enviarEmailCustom($event), 'slack' => $this->enviarSlackCustom($event), default => null, }; } // Suprime envio padrão (100% autônomo) $event->markAsHandled(); $event->suppressDefaultNotifications(); } }
Registre no EventServiceProvider:
protected $listen = [ \RiseTechApps\Monitoring\Events\ReportGenerated::class => [ \App\Listeners\EnviarMeuRelatorio::class, ], ];
Comparativo: Alertas vs Relatórios
| Recurso | Alertas (runtime) | Relatórios (periódicos) |
|---|---|---|
| Interface | AlertHandlerInterface |
ReportHandlerInterface |
| Evento | AlertTriggered |
ReportGenerated |
| Service | AlertService |
ReportService |
| Contexto | Evento individual (exceção, etc) | Dados agregados do período |
| Dados | IncomingEntry |
array $report + string $html |
| Canais | Email, Slack, Discord | Email, Slack, Discord |
Notificações Customizáveis (Alertas)
Além dos canais padrão (Slack, Discord, Email), você pode criar notificações customizadas usando Handlers ou ouvindo o evento AlertTriggered.
Método 1: Handler Customizado (Recomendado)
Crie uma classe implementando AlertHandlerInterface:
<?php namespace App\Monitoring\Handlers; use RiseTechApps\Monitoring\Contracts\AlertHandlerInterface; use RiseTechApps\Monitoring\Entry\IncomingEntry; class TelegramAlertHandler implements AlertHandlerInterface { public function send(string $type, IncomingEntry $entry, array $config = []): bool { $botToken = $config['bot_token'] ?? config('services.telegram.bot_token'); $chatId = $config['chat_id'] ?? config('services.telegram.chat_id'); $message = $this->formatMessage($type, $entry); $response = Http::post("https://api.telegram.org/bot{$botToken}/sendMessage", [ 'chat_id' => $chatId, 'text' => $message, 'parse_mode' => 'HTML', ]); return $response->successful(); } public function isConfigured(array $config = []): bool { return !empty($config['bot_token']) && !empty($config['chat_id']); } public function getName(): string { return 'telegram'; } private function formatMessage(string $type, IncomingEntry $entry): string { $content = $entry->content; return match ($type) { 'exception' => "<b>🚨 Exceção</b>\n" . "Classe: {$content['class']}\n" . "Mensagem: {$content['message']}", 'request' => "<b>⏱️ Requisição Lenta</b>\n" . "{$content['method']} {$content['uri']}\n" . "Duração: {$content['duration']}ms", default => "<b>Alerta:</b> {$type}", }; } }
Registre o handler em um ServiceProvider:
<?php namespace App\Providers; use App\Monitoring\Handlers\TelegramAlertHandler; use Illuminate\Support\ServiceProvider; use RiseTechApps\Monitoring\Services\Alerts\AlertService; class MonitoringServiceProvider extends ServiceProvider { public function boot(): void { // Registra o handler customizado AlertService::registerHandler('telegram', new TelegramAlertHandler()); } }
Configure o handler no config/monitoring.php:
'alerts' => [ 'enabled' => true, // ... configurações padrão ... // Handlers customizados 'custom_handlers' => [ 'telegram' => [ 'bot_token' => env('TELEGRAM_BOT_TOKEN'), 'chat_id' => env('TELEGRAM_CHAT_ID'), ], ], ],
Método 2: Event Listener
Ouça o evento AlertTriggered para executar ações customizadas:
<?php namespace App\Listeners; use RiseTechApps\Monitoring\Events\AlertTriggered; class SendPagerDutyNotification { public function handle(AlertTriggered $event): void { // Apenas para exceções críticas if ($event->type !== 'exception') { return; } $content = $event->entry->content; // Envia para PagerDuty Http::post(config('services.pagerduty.webhook'), [ 'routing_key' => config('services.pagerduty.key'), 'event_action' => 'trigger', 'payload' => [ 'summary' => $content['message'], 'severity' => 'critical', 'source' => $content['file'] ?? 'unknown', ], ]); // Marca como handled para pular notificações padrão (opcional) // $event->markAsHandled(); } }
Registre o listener no EventServiceProvider:
protected $listen = [ \RiseTechApps\Monitoring\Events\AlertTriggered::class => [ \App\Listeners\SendPagerDutyNotification::class, ], ];
Desabilitar Notificações Padrão
Para usar apenas notificações customizadas:
use RiseTechApps\Monitoring\Services\Alerts\AlertService; // Em um ServiceProvider::boot() AlertService::disableDefaultNotifications();
Para reabilitar:
AlertService::enableDefaultNotifications();
Ordem de Processamento
- Evento
AlertTriggeredé disparado → listeners podem processar - Se
$event->handled = true, notificações padrão são ignoradas - Handlers customizados são executados
- Notificações padrão (Slack/Discord/Email) são enviadas (se não desabilitadas)
Exemplo: Notificação para Múltiplos Canais
// Handler para Microsoft Teams class TeamsAlertHandler implements AlertHandlerInterface { public function send(string $type, IncomingEntry $entry, array $config = []): bool { $webhook = $config['webhook_url']; $card = [ '@type' => 'MessageCard', '@context' => 'https://schema.org/extensions', 'themeColor' => $this->getColorForType($type), 'summary' => "Alerta: {$type}", 'sections' => [ [ 'activityTitle' => "Alerta de Monitoramento: {$type}", 'facts' => $this->buildFacts($entry), ], ], ]; Http::post($webhook, $card); return true; } public function isConfigured(array $config = []): bool { return !empty($config['webhook_url']); } public function getName(): string { return 'teams'; } }
Performance Monitoring
Métricas avançadas de performance calculadas automaticamente.
Configuração
'performance' => [ 'track_memory_peaks' => true, 'track_db_connections' => true, 'track_cache_hits' => true, 'apdex' => [ 'threshold' => 500, // ms - satisfatório 'tolerable' => 2000, // ms - tolerável ], ],
Métricas Calculadas
Apdex Score
Mede satisfação do usuário (0.0 a 1.0):
1.0= Perfeito0.94-0.99= Excelente0.85-0.93= Bom0.70-0.84= Justo< 0.70= Ruim
Throughput
Requisições por minuto processadas.
Latência Percentil
| Métrica | Significado |
|---|---|
p50 (mediana) |
50% das requisições são mais rápidas que isso |
p95 |
95% das requisições são mais rápidas |
p99 |
99% das requisições são mais rápidas |
Exemplo de resposta
{
"apdex_score": 0.94,
"throughput_per_minute": 245,
"error_rate_percent": 0.5,
"latency": {
"p50": 120,
"p95": 450,
"p99": 890,
"avg": 180,
"min": 45,
"max": 1200
},
"memory": {
"peak_avg_mb": 64,
"peak_max_mb": 128
}
}
Filtros Avançados na API
Parâmetros de busca
# Filtrar por tipo e período GET /monitoring?type=exception&from=2025-01-01&to=2025-01-15 # Apenas exceções não resolvidas GET /monitoring?type=exception&unresolved=true # Ordenação personalizada GET /monitoring?sort=created_at&order=asc&per_page=25 # Busca full-text GET /monitoring/search?q=PaymentException # Busca por tipo específico GET /monitoring/search?q=TimeoutException&type=exception
Comparação de Períodos
GET /monitoring/compare?period1=last_7_days&period2=previous_7_days
Resposta:
{
"period1": {
"name": "last_7_days",
"data": { "total": 1250, "by_type": {...} }
},
"period2": {
"name": "previous_7_days",
"data": { "total": 980, "by_type": {...} }
},
"changes": {
"total_diff": 270,
"total_percent": 27.55
}
}
Política de Retenção Inteligente
Configure retenção diferenciada por tipo de dado.
Configuração
'retention' => [ 'days' => 90, // Padrão fallback // Políticas granulares 'granular' => [ 'exceptions' => 90, // Manter exceções por mais tempo 'requests' => 30, // Requisições por menos tempo 'jobs' => 60, 'queries' => 7, // Queries por pouco tempo 'cache' => 7, 'metrics' => 30, ], // Manter exceções não resolvidas além do prazo 'keep_unresolved' => true, ],
Comando de retenção
# Retenção padrão php artisan monitoring:retention # Com políticas granulares php artisan monitoring:retention --granular # Manter exceções não resolvidas php artisan monitoring:retention --keep-unresolved # Simular sem executar php artisan monitoring:retention --dry-run
Agendamento automático
// App/Console/Kernel.php protected function schedule(Schedule $schedule): void { $schedule->command('monitoring:retention --granular --force') ->dailyAt('02:00'); }
Exemplos de requisição:
# Todos os eventos GET /monitoring # Evento específico com relacionados GET /monitoring/018e4b2a-1234-7000-abcd-ef0123456789 # Filtrar por tipo GET /monitoring/type/exception GET /monitoring/type/request GET /monitoring/type/job # Listar tipos disponíveis POST /monitoring/tags
Exemplo Completo: Dashboard de Monitoramento
use RiseTechApps\Monitoring\Repository\Contracts\MonitoringRepositoryInterface; use RiseTechApps\Monitoring\Entry\EntryType; class MonitoringDashboardController extends Controller { public function __construct( protected MonitoringRepositoryInterface $monitoring ) {} public function index() { return response()->json([ 'resumo' => [ 'requisicoes' => $this->monitoring->getEventsByTypes(EntryType::REQUEST)->count(), 'excecoes' => $this->monitoring->getEventsByTypes(EntryType::EXCEPTION)->count(), 'jobs_falhos' => $this->monitoring->getEventsByTypes(EntryType::JOB) ->where('content.status', 'failed')->count(), ], 'ultimas_24h' => $this->monitoring->getLast24Hours(), 'ultimos_7d' => $this->monitoring->getLast7Days(), ]); } public function show(string $id) { return response()->json( $this->monitoring->getEventById($id) ); } public function byBatch(string $batchId) { // Útil para ver tudo que aconteceu em uma requisição específica: // request + events + jobs + gates disparados juntos return response()->json( $this->monitoring->getByBatch($batchId) ); } }
Diagnóstico e Troubleshooting
Testar Watchers (`monitoring:test-watchers)
Execute um diagnóstico completo para verificar se todos os watchers estão funcionando corretamente. O comando dispara eventos de teste e verifica se foram registrados no banco.
# Teste completo php artisan monitoring:test-watchers # Com detalhes php artisan monitoring:test-watchers --verbose # Aguardar mais tempo entre testes php artisan monitoring:test-watchers --wait=3 # Não limpar registros de teste (para debug) php artisan monitoring:test-watchers --no-cleanup
Testes executados
| Watcher | Evento de Teste | O que é verificado |
|---|---|---|
| Exception | Exception de teste | Captura de exceções |
| Query | SELECT simples | Monitoramento de queries |
| Cache | Write, Hit, Miss, Delete | Operações de cache |
| Log | Log::info() | Mensagens de log |
| Event | Evento de locale | Eventos disparados |
| Gate | Gate de teste | Autorizações |
| Mailable de teste | Envio de e-mail | |
| Notification | Notificação de teste | Notificações |
| HTTP Client | Request fake | Requisições HTTP |
Saída esperada
┌─────────────────────────────────────────────────┐
│ Monitoring — Teste de Watchers │
└─────────────────────────────────────────────────┘
✓ Monitoramento habilitado
Testando: Exception Watcher
✓ Evento disparado
Testando: Query Watcher
✓ Evento disparado
...
Verificando registros no banco...
✓ Exception Watcher: 1 registro(s) encontrado(s)
✓ Query Watcher: 1 registro(s) encontrado(s)
✓ Cache Watcher: 4 registro(s) encontrado(s)
...
─────────────────────────────────────────────────
RESUMO DOS TESTES
─────────────────────────────────────────────────
Total: 9 | Eventos disparados: 9 | Registros no DB: 8
┌─────────────────────────┬───────────────────┬────────────┐
│ Watcher │ Status │ Registros │
├─────────────────────────┼───────────────────┼────────────┤
│ Exception Watcher │ ✓ OK │ 1 │
│ Query Watcher │ ✓ OK │ 1 │
│ Cache Watcher │ ✓ OK │ 4 │
│ Log Watcher │ ✓ OK │ 1 │
│ ... │ ... │ ... │
└─────────────────────────┴───────────────────┴────────────┘
Possíveis problemas
"Monitoramento está DESABILITADO"
# Verifique a configuração cat .env | grep MONITORING_ENABLED # Ou habilite temporariamente php artisan tinker --execute="config(['monitoring.enabled' => true])"
Watcher não registra no banco
- Verifique se o watcher está habilitado em
config/monitoring.php - Confirme se o driver é
database(nãosingle) - Execute com
--wait=5para dar mais tempo ao buffer
"0 registros encontrados"
- Driver
singlegrava em arquivo, não no banco — isso é normal - Verifique
storage/logs/monitoring.logpara logs em arquivo
Canal de Log monitoring
O pacote registra automaticamente um canal de log chamado monitoring no Laravel. Você pode usá-lo diretamente com a facade Log:
use Illuminate\Support\Facades\Log; Log::channel('monitoring')->info('Mensagem de log.');
Os logs são gravados em storage/logs/monitoring.log.
Facade Logs
O pacote registra o alias Logs para a facade MonitoringFacade:
use Logs; // alias para MonitoringFacade Logs::disable(); Logs::isEnabled();
Changelog
Veja o CHANGELOG para o histórico completo de versões.
Contribuindo
Veja o CONTRIBUTING para detalhes sobre como contribuir com o projeto.
Licença
Este pacote é open-source, licenciado sob a MIT license.
Desenvolvido com ❤️ por RiseTechApps — apps@risetech.com.br