monitoring-for-laravel maintained by risetechapps
Monitoring for Laravel
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