@@ -40,6 +40,15 @@ export interface MetricMeter {
4040 */
4141 createGauge ( name : string , valueType ?: NumericMetricValueType , unit ?: string , description ?: string ) : MetricGauge ;
4242
43+ /**
44+ * Create a new up-down counter metric that supports adding signed values.
45+ *
46+ * @param name Name for the up-down counter metric.
47+ * @param unit Unit for the up-down counter metric. Optional.
48+ * @param description Description for the up-down counter metric. Optional.
49+ */
50+ createUpDownCounter ?( name : string , unit ?: string , description ?: string ) : MetricUpDownCounter ;
51+
4352 /**
4453 * Return a clone of this meter, with additional tags. All metrics created off the meter will
4554 * have the tags.
@@ -104,7 +113,7 @@ export type NumericMetricValueType = 'int' | 'float';
104113 *
105114 * @experimental The Metric API is an experimental feature and may be subject to change.
106115 */
107- export type MetricKind = 'counter' | 'histogram' | 'gauge' ;
116+ export type MetricKind = 'counter' | 'histogram' | 'gauge' | 'up-down-counter' ;
108117
109118/**
110119 * A metric that supports adding values as a counter.
@@ -181,6 +190,31 @@ export interface MetricGauge extends Metric {
181190 kind : 'gauge' ;
182191}
183192
193+ /**
194+ * A metric that supports adding signed values as an up-down counter.
195+ *
196+ * @experimental The Metric API is an experimental feature and may be subject to change.
197+ */
198+ export interface MetricUpDownCounter extends Metric {
199+ /**
200+ * Add the given value to the up-down counter. Value may be negative.
201+ *
202+ * @param value Value to add (can be positive or negative).
203+ * @param extraTags Extra tags if any.
204+ */
205+ add ( value : number , extraTags ?: MetricTags ) : void ;
206+
207+ /**
208+ * Return a clone of this up-down counter, with additional tags.
209+ *
210+ * @param tags Tags to append to existing tags.
211+ */
212+ withTags ( tags : MetricTags ) : MetricUpDownCounter ;
213+
214+ kind : 'up-down-counter' ;
215+ valueType : 'int' ;
216+ }
217+
184218////////////////////////////////////////////////////////////////////////////////////////////////////
185219
186220/**
@@ -248,6 +282,23 @@ class NoopMetricMeter implements MetricMeter {
248282 } ;
249283 }
250284
285+ createUpDownCounter ( name : string , unit ?: string , description ?: string ) : MetricUpDownCounter {
286+ return {
287+ name,
288+ unit,
289+ description,
290+
291+ kind : 'up-down-counter' ,
292+ valueType : 'int' ,
293+
294+ add ( _value , _extraTags ) { } ,
295+
296+ withTags ( _extraTags ) {
297+ return this ;
298+ } ,
299+ } ;
300+ }
301+
251302 withTags ( _extraTags : MetricTags ) : MetricMeter {
252303 return this ;
253304 }
@@ -326,6 +377,16 @@ export class MetricMeterWithComposedTags implements MetricMeter {
326377 return new MetricGaugeWithComposedTags ( parentGauge , this . contributors ) ;
327378 }
328379
380+ createUpDownCounter ( name : string , unit ?: string , description ?: string ) : MetricUpDownCounter {
381+ // FIXME: Remove this guard once up-down-counter support is complete on all MetricMeter
382+ // implementations and `createUpDownCounter` is no longer optional on MetricMeter.
383+ if ( ! this . parentMeter . createUpDownCounter ) {
384+ throw new Error ( 'createUpDownCounter is not supported by the underlying meter' ) ;
385+ }
386+ const parentCounter = this . parentMeter . createUpDownCounter ( name , unit , description ) ;
387+ return new MetricUpDownCounterWithComposedTags ( parentCounter , this . contributors ) ;
388+ }
389+
329390 withTags ( tags : MetricTags ) : MetricMeter {
330391 return MetricMeterWithComposedTags . compose ( this , tags ) ;
331392 }
@@ -443,6 +504,42 @@ class MetricGaugeWithComposedTags implements MetricGauge {
443504 }
444505}
445506
507+ /**
508+ * @internal
509+ * @hidden
510+ */
511+ class MetricUpDownCounterWithComposedTags implements MetricUpDownCounter {
512+ public readonly kind = 'up-down-counter' ;
513+ public readonly valueType = 'int' ;
514+
515+ constructor (
516+ private parentCounter : MetricUpDownCounter ,
517+ private contributors : MetricTagsOrFunc [ ]
518+ ) { }
519+
520+ add ( value : number , extraTags ?: MetricTags | undefined ) : void {
521+ this . parentCounter . add ( value , resolveTags ( this . contributors , extraTags ) ) ;
522+ }
523+
524+ withTags ( extraTags : MetricTags ) : MetricUpDownCounter {
525+ const contributors = appendToChain ( this . contributors , extraTags ) ;
526+ if ( contributors === undefined ) return this ;
527+ return new MetricUpDownCounterWithComposedTags ( this . parentCounter , contributors ) ;
528+ }
529+
530+ get name ( ) : string {
531+ return this . parentCounter . name ;
532+ }
533+
534+ get unit ( ) : string | undefined {
535+ return this . parentCounter . unit ;
536+ }
537+
538+ get description ( ) : string | undefined {
539+ return this . parentCounter . description ;
540+ }
541+ }
542+
446543function resolveTags ( contributors : MetricTagsOrFunc [ ] , extraTags ?: MetricTags ) : MetricTags {
447544 const resolved = { } ;
448545 for ( const contributor of contributors ) {
0 commit comments