@@ -194,7 +194,6 @@ class DogStatsDClient {
194
194
}
195
195
}
196
196
197
- // TODO: Handle arrays of tags and tags translation.
198
197
class MetricsAggregationClient {
199
198
constructor ( client ) {
200
199
this . _client = client
@@ -211,98 +210,132 @@ class MetricsAggregationClient {
211
210
}
212
211
213
212
reset ( ) {
214
- this . _counters = { }
215
- this . _gauges = { }
216
- this . _histograms = { }
213
+ this . _counters = new Map ( )
214
+ this . _gauges = new Map ( )
215
+ this . _histograms = new Map ( )
217
216
}
218
217
219
- distribution ( name , value , tag ) {
220
- this . _client . distribution ( name , value , tag && [ tag ] )
218
+ // TODO: Aggerate with a histogram and send the buckets to the client.
219
+ distribution ( name , value , tags ) {
220
+ this . _client . distribution ( name , value , tags )
221
221
}
222
222
223
- boolean ( name , value , tag ) {
224
- this . gauge ( name , value ? 1 : 0 , tag )
223
+ boolean ( name , value , tags ) {
224
+ this . gauge ( name , value ? 1 : 0 , tags )
225
225
}
226
226
227
- histogram ( name , value , tag ) {
228
- this . _histograms [ name ] = this . _histograms [ name ] || new Map ( )
227
+ histogram ( name , value , tags ) {
228
+ const node = this . _ensureTree ( this . _histograms , name , tags , null )
229
229
230
- if ( ! this . _histograms [ name ] . has ( tag ) ) {
231
- this . _histograms [ name ] . set ( tag , new Histogram ( ) )
230
+ if ( ! node . value ) {
231
+ node . value = new Histogram ( )
232
232
}
233
233
234
- this . _histograms [ name ] . get ( tag ) . record ( value )
234
+ node . value . record ( value )
235
235
}
236
236
237
- count ( name , count , tag , monotonic = true ) {
238
- if ( typeof tag === 'boolean' ) {
239
- monotonic = tag
240
- tag = undefined
237
+ count ( name , count , tags = [ ] , monotonic = true ) {
238
+ if ( typeof tags === 'boolean' ) {
239
+ monotonic = tags
240
+ tags = [ ]
241
241
}
242
242
243
- const map = monotonic ? this . _counters : this . _gauges
243
+ const container = monotonic ? this . _counters : this . _gauges
244
+ const node = this . _ensureTree ( container , name , tags , 0 )
244
245
245
- map [ name ] = map [ name ] || new Map ( )
246
-
247
- const value = map [ name ] . get ( tag ) || 0
248
-
249
- map [ name ] . set ( tag , value + count )
246
+ node . value = node . value + count
250
247
}
251
248
252
- gauge ( name , value , tag ) {
253
- this . _gauges [ name ] = this . _gauges [ name ] || new Map ( )
254
- this . _gauges [ name ] . set ( tag , value )
249
+ gauge ( name , value , tags ) {
250
+ const node = this . _ensureTree ( this . _gauges , name , tags , 0 )
251
+
252
+ node . value = value
255
253
}
256
254
257
- increment ( name , count = 1 , tag ) {
258
- this . count ( name , count , tag )
255
+ increment ( name , count = 1 , tags ) {
256
+ this . count ( name , count , tags )
259
257
}
260
258
261
- decrement ( name , count = 1 , tag ) {
262
- this . count ( name , - count , tag )
259
+ decrement ( name , count = 1 , tags ) {
260
+ this . count ( name , - count , tags )
263
261
}
264
262
265
263
_captureGauges ( ) {
266
- Object . keys ( this . _gauges ) . forEach ( name => {
267
- this . _gauges [ name ] . forEach ( ( value , tag ) => {
268
- this . _client . gauge ( name , value , tag && [ tag ] )
269
- } )
264
+ this . _captureTree ( this . _gauges , ( node , name , tags ) => {
265
+ this . _client . gauge ( name , node . value , tags )
270
266
} )
271
267
}
272
268
273
269
_captureCounters ( ) {
274
- Object . keys ( this . _counters ) . forEach ( name => {
275
- this . _counters [ name ] . forEach ( ( value , tag ) => {
276
- this . _client . increment ( name , value , tag && [ tag ] )
277
- } )
270
+ this . _captureTree ( this . _counters , ( node , name , tags ) => {
271
+ this . _client . increment ( name , node . value , tags )
278
272
} )
279
273
280
- this . _counters = { }
274
+ this . _counters . clear ( )
281
275
}
282
276
283
277
_captureHistograms ( ) {
284
- Object . keys ( this . _histograms ) . forEach ( name => {
285
- this . _histograms [ name ] . forEach ( ( stats , tag ) => {
286
- const tags = tag && [ tag ]
278
+ this . _captureTree ( this . _histograms , ( node , name , tags ) => {
279
+ let stats = node . value
287
280
288
- // Stats can contain garbage data when a value was never recorded.
289
- if ( stats . count === 0 ) {
290
- stats = { max : 0 , min : 0 , sum : 0 , avg : 0 , median : 0 , p95 : 0 , count : 0 , reset : stats . reset }
291
- }
281
+ // Stats can contain garbage data when a value was never recorded.
282
+ if ( stats . count === 0 ) {
283
+ stats = { max : 0 , min : 0 , sum : 0 , avg : 0 , median : 0 , p95 : 0 , count : 0 }
284
+ }
292
285
293
- this . _client . gauge ( `${ name } .min` , stats . min , tags )
294
- this . _client . gauge ( `${ name } .max` , stats . max , tags )
295
- this . _client . increment ( `${ name } .sum` , stats . sum , tags )
296
- this . _client . increment ( `${ name } .total` , stats . sum , tags )
297
- this . _client . gauge ( `${ name } .avg` , stats . avg , tags )
298
- this . _client . increment ( `${ name } .count` , stats . count , tags )
299
- this . _client . gauge ( `${ name } .median` , stats . median , tags )
300
- this . _client . gauge ( `${ name } .95percentile` , stats . p95 , tags )
286
+ this . _client . gauge ( `${ name } .min` , stats . min , tags )
287
+ this . _client . gauge ( `${ name } .max` , stats . max , tags )
288
+ this . _client . increment ( `${ name } .sum` , stats . sum , tags )
289
+ this . _client . increment ( `${ name } .total` , stats . sum , tags )
290
+ this . _client . gauge ( `${ name } .avg` , stats . avg , tags )
291
+ this . _client . increment ( `${ name } .count` , stats . count , tags )
292
+ this . _client . gauge ( `${ name } .median` , stats . median , tags )
293
+ this . _client . gauge ( `${ name } .95percentile` , stats . p95 , tags )
301
294
302
- stats . reset ( )
303
- } )
295
+ node . value . reset ( )
304
296
} )
305
297
}
298
+
299
+ _captureTree ( tree , fn ) {
300
+ for ( const [ name , root ] of tree ) {
301
+ this . _captureNode ( root , name , [ ] , fn )
302
+ }
303
+ }
304
+
305
+ _captureNode ( node , name , tags , fn ) {
306
+ if ( node . touched ) {
307
+ fn ( node , name , tags )
308
+ }
309
+
310
+ for ( const [ tag , next ] of node . nodes ) {
311
+ this . _captureNode ( next , name , tags . concat ( tag ) , fn )
312
+ }
313
+ }
314
+
315
+ _ensureTree ( tree , name , tags , value ) {
316
+ tags = tags ? [ ] . concat ( tags ) : [ ]
317
+
318
+ let node = this . _ensureNode ( tree , name , value )
319
+
320
+ for ( const tag of tags ) {
321
+ node = this . _ensureNode ( node . nodes , tag , value )
322
+ }
323
+
324
+ node . touched = true
325
+
326
+ return node
327
+ }
328
+
329
+ _ensureNode ( container , key , value ) {
330
+ let node = container . get ( key )
331
+
332
+ if ( ! node ) {
333
+ node = { nodes : new Map ( ) , touched : false , value }
334
+ container . set ( key , node )
335
+ }
336
+
337
+ return node
338
+ }
306
339
}
307
340
308
341
/**
@@ -324,45 +357,29 @@ class CustomMetrics {
324
357
}
325
358
326
359
increment ( stat , value = 1 , tags ) {
327
- for ( const tag of this . _normalizeTags ( tags ) ) {
328
- this . _client . increment ( stat , value , tag )
329
- }
360
+ this . _client . increment ( stat , value , CustomMetrics . tagTranslator ( tags ) )
330
361
}
331
362
332
363
decrement ( stat , value = 1 , tags ) {
333
- for ( const tag of this . _normalizeTags ( tags ) ) {
334
- this . _client . decrement ( stat , value , tag )
335
- }
364
+ this . _client . decrement ( stat , value , CustomMetrics . tagTranslator ( tags ) )
336
365
}
337
366
338
367
gauge ( stat , value , tags ) {
339
- for ( const tag of this . _normalizeTags ( tags ) ) {
340
- this . _client . gauge ( stat , value , tag )
341
- }
368
+ this . _client . gauge ( stat , value , CustomMetrics . tagTranslator ( tags ) )
342
369
}
343
370
344
371
distribution ( stat , value , tags ) {
345
- for ( const tag of this . _normalizeTags ( tags ) ) {
346
- this . _client . distribution ( stat , value , tag )
347
- }
372
+ this . _client . distribution ( stat , value , CustomMetrics . tagTranslator ( tags ) )
348
373
}
349
374
350
375
histogram ( stat , value , tags ) {
351
- for ( const tag of this . _normalizeTags ( tags ) ) {
352
- this . _client . histogram ( stat , value , tag )
353
- }
376
+ this . _client . histogram ( stat , value , CustomMetrics . tagTranslator ( tags ) )
354
377
}
355
378
356
379
flush ( ) {
357
380
return this . _client . flush ( )
358
381
}
359
382
360
- _normalizeTags ( tags ) {
361
- tags = CustomMetrics . tagTranslator ( tags )
362
-
363
- return tags . length === 0 ? [ undefined ] : tags
364
- }
365
-
366
383
/**
367
384
* Exposing { tagName: 'tagValue' } to the end user
368
385
* These are translated into [ 'tagName:tagValue' ] for internal use
0 commit comments