feat: add HTTP metrics middleware for Prometheus
- Add src/middleware/metrics.js with http_requests_total, http_errors_total, etc. - Import and use metricsMiddleware in index.js 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
bb0aa2fa44
commit
451cd67455
4
index.js
4
index.js
|
|
@ -5,6 +5,7 @@ import helmet from "helmet";
|
||||||
import morgan from "morgan";
|
import morgan from "morgan";
|
||||||
import client from "prom-client";
|
import client from "prom-client";
|
||||||
import { pool } from "./db.js";
|
import { pool } from "./db.js";
|
||||||
|
import { metricsMiddleware } from "./src/middleware/metrics.js";
|
||||||
|
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|
@ -19,6 +20,9 @@ app.use(helmet());
|
||||||
app.use(morgan("tiny"));
|
app.use(morgan("tiny"));
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
|
|
||||||
|
// Middleware de métriques HTTP (doit être avant les routes)
|
||||||
|
app.use(metricsMiddleware);
|
||||||
|
|
||||||
app.get("/health", (req, res) => {
|
app.get("/health", (req, res) => {
|
||||||
res.status(200).json({ status: "ok" });
|
res.status(200).json({ status: "ok" });
|
||||||
});
|
});
|
||||||
|
|
|
||||||
108
src/middleware/metrics.js
Normal file
108
src/middleware/metrics.js
Normal file
|
|
@ -0,0 +1,108 @@
|
||||||
|
import client from "prom-client";
|
||||||
|
|
||||||
|
// Compteur de requêtes HTTP totales
|
||||||
|
const httpRequestsTotal = new client.Counter({
|
||||||
|
name: "http_requests_total",
|
||||||
|
help: "Total number of HTTP requests",
|
||||||
|
labelNames: ["method", "route", "status_code"],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Histogramme de durée des requêtes
|
||||||
|
const httpRequestDuration = new client.Histogram({
|
||||||
|
name: "http_request_duration_seconds",
|
||||||
|
help: "Duration of HTTP requests in seconds",
|
||||||
|
labelNames: ["method", "route", "status_code"],
|
||||||
|
buckets: [0.001, 0.005, 0.015, 0.05, 0.1, 0.2, 0.3, 0.4, 0.5, 1, 2, 5],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Compteur de requêtes en cours
|
||||||
|
const httpRequestsInProgress = new client.Gauge({
|
||||||
|
name: "http_requests_in_progress",
|
||||||
|
help: "Number of HTTP requests currently being processed",
|
||||||
|
labelNames: ["method"],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Compteur d'erreurs HTTP
|
||||||
|
const httpErrorsTotal = new client.Counter({
|
||||||
|
name: "http_errors_total",
|
||||||
|
help: "Total number of HTTP errors (4xx and 5xx)",
|
||||||
|
labelNames: ["method", "route", "status_code"],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Taille des réponses
|
||||||
|
const httpResponseSize = new client.Histogram({
|
||||||
|
name: "http_response_size_bytes",
|
||||||
|
help: "Size of HTTP responses in bytes",
|
||||||
|
labelNames: ["method", "route"],
|
||||||
|
buckets: [100, 500, 1000, 5000, 10000, 50000, 100000, 500000],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Fonction pour normaliser les routes (éviter la cardinalité élevée)
|
||||||
|
const normalizeRoute = (req) => {
|
||||||
|
// Si la route est définie par Express, l'utiliser
|
||||||
|
if (req.route && req.route.path) {
|
||||||
|
return req.baseUrl + req.route.path;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sinon, normaliser le path en remplaçant les IDs par des placeholders
|
||||||
|
let path = req.path;
|
||||||
|
|
||||||
|
// Remplacer les UUIDs
|
||||||
|
path = path.replace(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi, ":id");
|
||||||
|
|
||||||
|
// Remplacer les nombres (IDs numériques)
|
||||||
|
path = path.replace(/\/\d+/g, "/:id");
|
||||||
|
|
||||||
|
// Remplacer les codes de ticket (format spécifique)
|
||||||
|
path = path.replace(/\/[A-Z0-9]{6,}/g, "/:code");
|
||||||
|
|
||||||
|
return path;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Middleware de métriques
|
||||||
|
export const metricsMiddleware = (req, res, next) => {
|
||||||
|
// Ignorer les endpoints de métriques et health check
|
||||||
|
if (req.path === "/metrics" || req.path === "/health") {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
|
const startTime = Date.now();
|
||||||
|
|
||||||
|
// Incrémenter les requêtes en cours
|
||||||
|
httpRequestsInProgress.inc({ method: req.method });
|
||||||
|
|
||||||
|
// Capturer la fin de la réponse
|
||||||
|
res.on("finish", () => {
|
||||||
|
const duration = (Date.now() - startTime) / 1000; // En secondes
|
||||||
|
const route = normalizeRoute(req);
|
||||||
|
const statusCode = res.statusCode.toString();
|
||||||
|
const labels = {
|
||||||
|
method: req.method,
|
||||||
|
route: route,
|
||||||
|
status_code: statusCode,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Enregistrer les métriques
|
||||||
|
httpRequestsTotal.inc(labels);
|
||||||
|
httpRequestDuration.observe(labels, duration);
|
||||||
|
httpRequestsInProgress.dec({ method: req.method });
|
||||||
|
|
||||||
|
// Compter les erreurs
|
||||||
|
if (res.statusCode >= 400) {
|
||||||
|
httpErrorsTotal.inc(labels);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Taille de la réponse (si disponible)
|
||||||
|
const contentLength = res.get("Content-Length");
|
||||||
|
if (contentLength) {
|
||||||
|
httpResponseSize.observe(
|
||||||
|
{ method: req.method, route: route },
|
||||||
|
parseInt(contentLength, 10)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
next();
|
||||||
|
};
|
||||||
|
|
||||||
|
export default metricsMiddleware;
|
||||||
Loading…
Reference in New Issue
Block a user