57 lines
2.6 KiB
TypeScript
57 lines
2.6 KiB
TypeScript
import express from 'express';
|
|
import { logger } from '../logger.js';
|
|
import { ConfigManager } from '../config-manager.js';
|
|
import { createWorkerRegistry } from '../metrics/registry.js';
|
|
import { createWorkerMetrics, type WorkerMetrics } from '../metrics/worker-metrics.js';
|
|
import { createMetricsHandler } from '../metrics/http-handler.js';
|
|
|
|
/**
|
|
* Phase 3b: Prometheus /metrics endpoint, extracted verbatim from
|
|
* createCoreServer (bridge/server.ts). Mounted BEFORE any auth middleware so
|
|
* the standard Prometheus scrape job works without a session cookie.
|
|
* Restrict scrape access at the reverse proxy / firewall layer (see help
|
|
* doc). Disabled by provider.metrics.enabled=false in config.yaml.
|
|
*/
|
|
export function setupMetricsSubsystem(
|
|
app: express.Application,
|
|
configManager: ConfigManager | undefined,
|
|
): {
|
|
workerMetrics: WorkerMetrics | null;
|
|
/** Phase 3c: shared prom-client registry so the same-process gateway mount
|
|
* can register its gateway_* counters into the same /metrics endpoint
|
|
* (one scrape serves both worker and gateway). Null when metrics are
|
|
* disabled. */
|
|
sharedPromRegistry: import('prom-client').Registry | null;
|
|
} {
|
|
const appConfig = (() => {
|
|
try { return configManager?.getConfig() ?? null; } catch {
|
|
// Configuration errors may contain credentials; report the fallback only.
|
|
logger.warn('[bridge] failed to read metrics configuration; using default metrics settings');
|
|
return null;
|
|
}
|
|
})();
|
|
const metricsCfg = appConfig?.provider?.metrics;
|
|
let workerMetrics: WorkerMetrics | null = null;
|
|
let sharedPromRegistry: import('prom-client').Registry | null = null;
|
|
if (metricsCfg?.enabled !== false) {
|
|
const prefix = metricsCfg?.prefix ?? 'aao_worker';
|
|
sharedPromRegistry = createWorkerRegistry(prefix);
|
|
workerMetrics = createWorkerMetrics(sharedPromRegistry, prefix);
|
|
// Phase 3b post-review: gate /metrics on (1) bearer token if set,
|
|
// (2) otherwise client-IP allowlist (default localhost). Labels
|
|
// like `worker_id` / `backend_id` would leak otherwise.
|
|
const metricsAuth = {
|
|
bearerToken: metricsCfg?.bearerToken,
|
|
allowedHosts: metricsCfg?.allowedHosts,
|
|
};
|
|
app.get('/metrics', createMetricsHandler(sharedPromRegistry, metricsAuth));
|
|
const authMode = metricsAuth.bearerToken
|
|
? 'bearer'
|
|
: `ip-allowlist=${(metricsAuth.allowedHosts ?? ['127.0.0.1', '::1', 'localhost']).join(',')}`;
|
|
logger.info(`[bridge] worker metrics enabled prefix=${prefix} auth=${authMode}`);
|
|
} else {
|
|
logger.info('[bridge] worker metrics disabled (provider.metrics.enabled=false)');
|
|
}
|
|
return { workerMetrics, sharedPromRegistry };
|
|
}
|