@@ -194,7 +194,6 @@ class DogStatsDClient {
194194 }
195195}
196196
197- // TODO: Handle arrays of tags and tags translation.
198197class MetricsAggregationClient {
199198 constructor ( client ) {
200199 this . _client = client
@@ -211,98 +210,132 @@ class MetricsAggregationClient {
211210 }
212211
213212 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 ( )
217216 }
218217
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 )
221221 }
222222
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 )
225225 }
226226
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 )
229229
230- if ( ! this . _histograms [ name ] . has ( tag ) ) {
231- this . _histograms [ name ] . set ( tag , new Histogram ( ) )
230+ if ( ! node . value ) {
231+ node . value = new Histogram ( )
232232 }
233233
234- this . _histograms [ name ] . get ( tag ) . record ( value )
234+ node . value . record ( value )
235235 }
236236
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 = [ ]
241241 }
242242
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 )
244245
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
250247 }
251248
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
255253 }
256254
257- increment ( name , count = 1 , tag ) {
258- this . count ( name , count , tag )
255+ increment ( name , count = 1 , tags ) {
256+ this . count ( name , count , tags )
259257 }
260258
261- decrement ( name , count = 1 , tag ) {
262- this . count ( name , - count , tag )
259+ decrement ( name , count = 1 , tags ) {
260+ this . count ( name , - count , tags )
263261 }
264262
265263 _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 )
270266 } )
271267 }
272268
273269 _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 )
278272 } )
279273
280- this . _counters = { }
274+ this . _counters . clear ( )
281275 }
282276
283277 _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
287280
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+ }
292285
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 )
301294
302- stats . reset ( )
303- } )
295+ node . value . reset ( )
304296 } )
305297 }
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+ }
306339}
307340
308341/**
@@ -324,45 +357,29 @@ class CustomMetrics {
324357 }
325358
326359 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 ) )
330361 }
331362
332363 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 ) )
336365 }
337366
338367 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 ) )
342369 }
343370
344371 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 ) )
348373 }
349374
350375 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 ) )
354377 }
355378
356379 flush ( ) {
357380 return this . _client . flush ( )
358381 }
359382
360- _normalizeTags ( tags ) {
361- tags = CustomMetrics . tagTranslator ( tags )
362-
363- return tags . length === 0 ? [ undefined ] : tags
364- }
365-
366383 /**
367384 * Exposing { tagName: 'tagValue' } to the end user
368385 * These are translated into [ 'tagName:tagValue' ] for internal use
0 commit comments