@@ -18,7 +18,8 @@ var http = require("http"),
18
18
util = require ( "util" ) ,
19
19
URL = require ( "url" ) ,
20
20
defaultLogger = require ( "./log" ) . defaultLogger ,
21
- querystring = require ( "querystring" ) ;
21
+ querystring = require ( "querystring" ) ,
22
+ metrics = require ( "./metrics" ) ;
22
23
23
24
function bound ( that , method ) {
24
25
// bind a method, to ensure `this=that` when it is called
@@ -159,23 +160,11 @@ class ConfigurableProxy extends EventEmitter {
159
160
this . errorTarget = this . errorTarget + "/" ; // ensure trailing /
160
161
}
161
162
this . errorPath = options . errorPath || path . join ( __dirname , "error" ) ;
162
- if ( options . statsd ) {
163
- this . statsd = options . statsd ;
163
+
164
+ if ( this . options . enableMetrics ) {
165
+ this . metrics = new metrics . Metrics ( ) ;
164
166
} else {
165
- // Mock the statsd object, rather than pepper the codebase with
166
- // null checks. FIXME: Maybe use a JS Proxy object (if available?)
167
- this . statsd = {
168
- increment : function ( ) { } ,
169
- decrement : function ( ) { } ,
170
- timing : function ( ) { } ,
171
- gauge : function ( ) { } ,
172
- set : function ( ) { } ,
173
- createTimer : function ( ) {
174
- return {
175
- stop : function ( ) { } ,
176
- } ;
177
- } ,
178
- } ;
167
+ this . metrics = new metrics . MockMetrics ( ) ;
179
168
}
180
169
181
170
if ( this . options . defaultTarget ) {
@@ -224,6 +213,12 @@ class ConfigurableProxy extends EventEmitter {
224
213
this . apiServer = http . createServer ( apiCallback ) ;
225
214
}
226
215
216
+ // handle metrics
217
+ if ( this . options . enableMetrics ) {
218
+ var metricsCallback = logErrors ( that . handleMetrics ) ;
219
+ this . metricsServer = http . createServer ( metricsCallback ) ;
220
+ }
221
+
227
222
// proxy requests separately
228
223
var proxyCallback = logErrors ( this . handleProxyWeb ) ;
229
224
if ( this . options . ssl ) {
@@ -235,7 +230,7 @@ class ConfigurableProxy extends EventEmitter {
235
230
this . proxyServer . on ( "upgrade" , bound ( this , this . handleProxyWs ) ) ;
236
231
237
232
this . proxy . on ( "proxyRes" , function ( proxyRes , req , res ) {
238
- that . statsd . increment ( "requests." + proxyRes . statusCode , 1 ) ;
233
+ that . metrics . requestsProxyCount . labels ( proxyRes . statusCode ) . inc ( ) ;
239
234
} ) ;
240
235
}
241
236
@@ -265,8 +260,8 @@ class ConfigurableProxy extends EventEmitter {
265
260
var that = this ;
266
261
267
262
return this . _routes . add ( path , data ) . then ( ( ) => {
268
- this . updateLastActivity ( path ) ;
269
- this . log . info ( "Route added %s -> %s" , path , data . target ) ;
263
+ that . updateLastActivity ( path ) ;
264
+ that . log . info ( "Route added %s -> %s" , path , data . target ) ;
270
265
} ) ;
271
266
}
272
267
@@ -341,7 +336,7 @@ class ConfigurableProxy extends EventEmitter {
341
336
342
337
res . write ( JSON . stringify ( results ) ) ;
343
338
res . end ( ) ;
344
- that . statsd . increment ( "api.route.get" , 1 ) ;
339
+ that . metrics . apiRouteGetCount . inc ( ) ;
345
340
} ) ;
346
341
}
347
342
@@ -359,7 +354,7 @@ class ConfigurableProxy extends EventEmitter {
359
354
return this . addRoute ( path , data ) . then ( function ( ) {
360
355
res . writeHead ( 201 ) ;
361
356
res . end ( ) ;
362
- that . statsd . increment ( "api.route.add" , 1 ) ;
357
+ that . metrics . apiRouteAddCount . inc ( ) ;
363
358
} ) ;
364
359
}
365
360
@@ -378,19 +373,19 @@ class ConfigurableProxy extends EventEmitter {
378
373
return p . then ( ( ) => {
379
374
res . writeHead ( code ) ;
380
375
res . end ( ) ;
381
- this . statsd . increment ( "api.route.delete" , 1 ) ;
376
+ this . metrics . apiRouteDeleteCount . inc ( ) ;
382
377
} ) ;
383
378
} ) ;
384
379
}
385
380
386
381
targetForReq ( req ) {
387
- var timer = this . statsd . createTimer ( "find_target_for_req" ) ;
382
+ var metricsTimerEnd = this . metrics . findTargetForReqSummary . startTimer ( ) ;
388
383
// return proxy target for a given url path
389
384
var basePath = this . hostRouting ? "/" + parseHost ( req ) : "" ;
390
385
var path = basePath + decodeURIComponent ( URL . parse ( req . url ) . pathname ) ;
391
386
392
387
return this . _routes . getTarget ( path ) . then ( function ( route ) {
393
- timer . stop ( ) ;
388
+ metricsTimerEnd ( ) ;
394
389
if ( route ) {
395
390
return {
396
391
prefix : route . prefix ,
@@ -401,7 +396,7 @@ class ConfigurableProxy extends EventEmitter {
401
396
}
402
397
403
398
updateLastActivity ( prefix ) {
404
- var timer = this . statsd . createTimer ( "last_activity_updating" ) ;
399
+ var metricsTimerEnd = this . metrics . lastActivityUpdatingSummary . startTimer ( ) ;
405
400
var routes = this . _routes ;
406
401
407
402
return routes
@@ -411,7 +406,7 @@ class ConfigurableProxy extends EventEmitter {
411
406
return routes . update ( prefix , { last_activity : new Date ( ) } ) ;
412
407
}
413
408
} )
414
- . then ( timer . stop ) ;
409
+ . then ( metricsTimerEnd ) ;
415
410
}
416
411
417
412
_handleProxyErrorDefault ( code , kind , req , res ) {
@@ -430,7 +425,7 @@ class ConfigurableProxy extends EventEmitter {
430
425
// /404?url=%2Fuser%2Ffoo
431
426
432
427
var errMsg = "" ;
433
- this . statsd . increment ( "requests." + code , 1 ) ;
428
+ this . metrics . requestsProxyCount . labels ( code ) . inc ( ) ;
434
429
if ( e ) {
435
430
// avoid stack traces on known not-our-problem errors:
436
431
// ECONNREFUSED, EHOSTUNREACH (backend isn't there)
@@ -512,7 +507,7 @@ class ConfigurableProxy extends EventEmitter {
512
507
this . _handleProxyErrorDefault ( code , kind , req , res ) ;
513
508
return ;
514
509
}
515
- if ( res . writableEnded ) return ; // response already done
510
+ if ( ! res . writable ) return ; // response already done
516
511
if ( res . writeHead ) res . writeHead ( code , { "Content-Type" : "text/html" } ) ;
517
512
if ( res . write ) res . write ( data ) ;
518
513
if ( res . end ) res . end ( ) ;
@@ -603,15 +598,15 @@ class ConfigurableProxy extends EventEmitter {
603
598
604
599
handleProxyWs ( req , socket , head ) {
605
600
// Proxy a websocket request
606
- this . statsd . increment ( "requests.ws" , 1 ) ;
601
+ this . metrics . requestsWsCount . inc ( ) ;
607
602
return this . handleProxy ( "ws" , req , socket , head ) ;
608
603
}
609
604
610
605
handleProxyWeb ( req , res ) {
611
606
this . handleHealthCheck ( req , res ) ;
612
607
if ( res . finished ) return ;
613
608
// Proxy a web request
614
- this . statsd . increment ( "requests.web" , 1 ) ;
609
+ this . metrics . requestsWebCount . inc ( ) ;
615
610
return this . handleProxy ( "web" , req , res ) ;
616
611
}
617
612
@@ -623,11 +618,18 @@ class ConfigurableProxy extends EventEmitter {
623
618
}
624
619
}
625
620
621
+ handleMetrics ( req , res ) {
622
+ if ( req . url === "/metrics" ) {
623
+ return this . metrics . render ( res ) ;
624
+ }
625
+ fail ( req , res , 404 ) ;
626
+ }
627
+
626
628
handleApiRequest ( req , res ) {
627
629
// Handle a request to the REST API
628
- this . statsd . increment ( "requests.api" , 1 ) ;
629
630
if ( res ) {
630
631
res . on ( "finish" , ( ) => {
632
+ this . metrics . requestsApiCount . labels ( res . statusCode ) . inc ( ) ;
631
633
this . logResponse ( req , res ) ;
632
634
} ) ;
633
635
}
0 commit comments