304 lines
7 KiB
TypeScript
304 lines
7 KiB
TypeScript
/**
|
|
* Monitoring routes for system health and metrics
|
|
*/
|
|
|
|
import { Hono } from 'hono';
|
|
import type { IServiceContainer } from '@stock-bot/handlers';
|
|
import { MonitoringService } from '../services/monitoring.service';
|
|
|
|
export function createMonitoringRoutes(container: IServiceContainer) {
|
|
const monitoring = new Hono();
|
|
const monitoringService = new MonitoringService(container);
|
|
|
|
/**
|
|
* Get overall system health
|
|
*/
|
|
monitoring.get('/', async c => {
|
|
try {
|
|
const health = await monitoringService.getSystemHealth();
|
|
|
|
// Set appropriate status code based on health
|
|
const statusCode =
|
|
health.status === 'healthy' ? 200 : health.status === 'degraded' ? 503 : 500;
|
|
|
|
return c.json(health, statusCode);
|
|
} catch (error) {
|
|
return c.json(
|
|
{
|
|
status: 'error',
|
|
message: 'Failed to retrieve system health',
|
|
error: error instanceof Error ? error.message : 'Unknown error',
|
|
},
|
|
500
|
|
);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Get cache/Dragonfly statistics
|
|
*/
|
|
monitoring.get('/cache', async c => {
|
|
try {
|
|
const stats = await monitoringService.getCacheStats();
|
|
return c.json(stats);
|
|
} catch (error) {
|
|
return c.json(
|
|
{
|
|
error: 'Failed to retrieve cache statistics',
|
|
message: error instanceof Error ? error.message : 'Unknown error',
|
|
},
|
|
500
|
|
);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Get queue statistics
|
|
*/
|
|
monitoring.get('/queues', async c => {
|
|
try {
|
|
const stats = await monitoringService.getQueueStats();
|
|
return c.json({ queues: stats });
|
|
} catch (error) {
|
|
return c.json(
|
|
{
|
|
error: 'Failed to retrieve queue statistics',
|
|
message: error instanceof Error ? error.message : 'Unknown error',
|
|
},
|
|
500
|
|
);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Get specific queue statistics
|
|
*/
|
|
monitoring.get('/queues/:name', async c => {
|
|
try {
|
|
const queueName = c.req.param('name');
|
|
const stats = await monitoringService.getQueueStats();
|
|
const queueStats = stats.find(q => q.name === queueName);
|
|
|
|
if (!queueStats) {
|
|
return c.json(
|
|
{
|
|
error: 'Queue not found',
|
|
message: `Queue '${queueName}' does not exist`,
|
|
},
|
|
404
|
|
);
|
|
}
|
|
|
|
return c.json(queueStats);
|
|
} catch (error) {
|
|
return c.json(
|
|
{
|
|
error: 'Failed to retrieve queue statistics',
|
|
message: error instanceof Error ? error.message : 'Unknown error',
|
|
},
|
|
500
|
|
);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Get database statistics
|
|
*/
|
|
monitoring.get('/databases', async c => {
|
|
try {
|
|
const stats = await monitoringService.getDatabaseStats();
|
|
return c.json({ databases: stats });
|
|
} catch (error) {
|
|
return c.json(
|
|
{
|
|
error: 'Failed to retrieve database statistics',
|
|
message: error instanceof Error ? error.message : 'Unknown error',
|
|
},
|
|
500
|
|
);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Get specific database statistics
|
|
*/
|
|
monitoring.get('/databases/:type', async c => {
|
|
try {
|
|
const dbType = c.req.param('type') as 'postgres' | 'mongodb' | 'questdb';
|
|
const stats = await monitoringService.getDatabaseStats();
|
|
const dbStats = stats.find(db => db.type === dbType);
|
|
|
|
if (!dbStats) {
|
|
return c.json(
|
|
{
|
|
error: 'Database not found',
|
|
message: `Database type '${dbType}' not found or not enabled`,
|
|
},
|
|
404
|
|
);
|
|
}
|
|
|
|
return c.json(dbStats);
|
|
} catch (error) {
|
|
return c.json(
|
|
{
|
|
error: 'Failed to retrieve database statistics',
|
|
message: error instanceof Error ? error.message : 'Unknown error',
|
|
},
|
|
500
|
|
);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Get service metrics
|
|
*/
|
|
monitoring.get('/metrics', async c => {
|
|
try {
|
|
const metrics = await monitoringService.getServiceMetrics();
|
|
return c.json(metrics);
|
|
} catch (error) {
|
|
return c.json(
|
|
{
|
|
error: 'Failed to retrieve service metrics',
|
|
message: error instanceof Error ? error.message : 'Unknown error',
|
|
},
|
|
500
|
|
);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Get detailed cache info (Redis INFO command output)
|
|
*/
|
|
monitoring.get('/cache/info', async c => {
|
|
try {
|
|
if (!container.cache) {
|
|
return c.json(
|
|
{
|
|
error: 'Cache not available',
|
|
message: 'Cache service is not enabled',
|
|
},
|
|
503
|
|
);
|
|
}
|
|
|
|
const info = await container.cache.info();
|
|
const stats = await monitoringService.getCacheStats();
|
|
|
|
return c.json({
|
|
parsed: stats,
|
|
raw: info,
|
|
});
|
|
} catch (error) {
|
|
return c.json(
|
|
{
|
|
error: 'Failed to retrieve cache info',
|
|
message: error instanceof Error ? error.message : 'Unknown error',
|
|
},
|
|
500
|
|
);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Health check endpoint for monitoring
|
|
*/
|
|
monitoring.get('/ping', c => {
|
|
return c.json({
|
|
status: 'ok',
|
|
timestamp: new Date().toISOString(),
|
|
service: 'monitoring',
|
|
});
|
|
});
|
|
|
|
/**
|
|
* Get service status for all microservices
|
|
*/
|
|
monitoring.get('/services', async c => {
|
|
try {
|
|
const services = await monitoringService.getServiceStatus();
|
|
return c.json({ services });
|
|
} catch (error) {
|
|
return c.json(
|
|
{
|
|
error: 'Failed to retrieve service status',
|
|
message: error instanceof Error ? error.message : 'Unknown error',
|
|
},
|
|
500
|
|
);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Get proxy statistics
|
|
*/
|
|
monitoring.get('/proxies', async c => {
|
|
try {
|
|
const stats = await monitoringService.getProxyStats();
|
|
return c.json(stats || { enabled: false });
|
|
} catch (error) {
|
|
return c.json(
|
|
{
|
|
error: 'Failed to retrieve proxy statistics',
|
|
message: error instanceof Error ? error.message : 'Unknown error',
|
|
},
|
|
500
|
|
);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Get comprehensive system overview
|
|
*/
|
|
monitoring.get('/overview', async c => {
|
|
try {
|
|
const overview = await monitoringService.getSystemOverview();
|
|
return c.json(overview);
|
|
} catch (error) {
|
|
return c.json(
|
|
{
|
|
error: 'Failed to retrieve system overview',
|
|
message: error instanceof Error ? error.message : 'Unknown error',
|
|
},
|
|
500
|
|
);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Test direct BullMQ queue access
|
|
*/
|
|
monitoring.get('/test/queue/:name', async c => {
|
|
const queueName = c.req.param('name');
|
|
const { Queue } = await import('bullmq');
|
|
|
|
const connection = {
|
|
host: 'localhost',
|
|
port: 6379,
|
|
db: 0, // All queues in DB 0
|
|
};
|
|
|
|
const queue = new Queue(queueName, { connection });
|
|
|
|
try {
|
|
const counts = await queue.getJobCounts();
|
|
await queue.close();
|
|
return c.json({
|
|
queueName,
|
|
counts,
|
|
});
|
|
} catch (error: any) {
|
|
await queue.close();
|
|
return c.json(
|
|
{
|
|
queueName,
|
|
error: error.message,
|
|
},
|
|
500
|
|
);
|
|
}
|
|
});
|
|
|
|
return monitoring;
|
|
}
|