@@ -45,6 +45,32 @@ const app = express();
4545// Collect default metrics (Node.js process metrics, etc.)
4646client . collectDefaultMetrics ( ) ;
4747
48+ // Normalize a path to reduce metrics label cardinality. Any dynamic-looking
49+ // segment (numbers, long hex/base64-ish tokens, UUIDs) is replaced with a
50+ // placeholder. If Express matched a route we prefer route.path which is
51+ // already a pattern (e.g. "/user/:id").
52+ function normalizePath ( req : express . Request ) : string {
53+ // If Express has a route pattern, use it (lowest cardinality already)
54+ const routePath = ( req as any ) . route ?. path ; // eslint-disable-line @typescript-eslint/no-explicit-any
55+ if ( routePath ) return routePath ;
56+
57+ const raw = req . path || "/" ;
58+ const uuidRe = / ^ [ 0 - 9 a - f ] { 8 } - [ 0 - 9 a - f ] { 4 } - [ 1 - 5 ] [ 0 - 9 a - f ] { 3 } - [ 8 9 a b ] [ 0 - 9 a - f ] { 3 } - [ 0 - 9 a - f ] { 12 } $ / i;
59+ const hexRe = / ^ [ 0 - 9 a - f A - F ] { 8 , } $ / ; // long-ish hex
60+ const base64ishRe = / ^ [ 0 - 9 a - z A - Z _ - ] { 10 , } $ / ; // tokens
61+ return raw
62+ . split ( "/" )
63+ . map ( ( seg ) => {
64+ if ( ! seg ) return seg ;
65+ if ( / ^ [ 0 - 9 ] + $ / . test ( seg ) ) return ":int" ;
66+ if ( uuidRe . test ( seg ) ) return ":uuid" ;
67+ if ( hexRe . test ( seg ) ) return ":hex" ;
68+ if ( base64ishRe . test ( seg ) && seg . length > 16 ) return ":tok" ;
69+ return seg ;
70+ } )
71+ . join ( "/" ) || "/" ;
72+ }
73+
4874// Custom metrics
4975const requestCounter = new client . Counter ( {
5076 name : "salt_service_requests_total" ,
@@ -62,7 +88,7 @@ const requestDuration = new client.Histogram({
6288app . use ( ( req , res , next ) => {
6389 const end = requestDuration . startTimer ( ) ;
6490 res . on ( "finish" , ( ) => {
65- const labels = { method : req . method , path : req . route ?. path || req . path , status : res . statusCode . toString ( ) } ;
91+ const labels = { method : req . method , path : normalizePath ( req ) , status : res . statusCode . toString ( ) } ;
6692 requestCounter . inc ( labels ) ;
6793 end ( labels ) ;
6894 } ) ;
@@ -121,7 +147,7 @@ app.listen(mainPort, () => {
121147} ) ;
122148
123149// Separate metrics server on port 9090
124- const METRICS_PORT = 9090 ;
150+ const METRICS_PORT = process . env . METRICS_PORT || 9090 ;
125151const metricsApp = express ( ) ;
126152metricsApp . get ( "/metrics" , async ( _req , res ) => {
127153 try {
0 commit comments