11package io .prometheus .client ;
22
33import java .util .ArrayList ;
4- import java .util .concurrent .ConcurrentHashMap ;
5- import java .util .concurrent .ConcurrentMap ;
64import java .util .Arrays ;
75import java .util .List ;
6+ import io .prometheus .client .ConcurrentChildMap .ConcurrentChildHashMap ;
87
98/**
109 * Common functionality for {@link Gauge}, {@link Counter}, {@link Summary} and {@link Histogram}.
4645 * by each. If the cardinality is in the hundreds, you may wish to consider removing the breakout
4746 * by one of the dimensions altogether.
4847 */
49- public abstract class SimpleCollector <Child > extends Collector {
48+ public abstract class SimpleCollector <Child > extends Collector implements ConcurrentChildMap . ChildFactory < Child > {
5049 protected final String fullname ;
5150 protected final String help ;
5251 protected final List <String > labelNames ;
5352
54- protected final ConcurrentMap < List < String >, Child > children = new ConcurrentHashMap < List < String >, Child >() ;
53+ protected final ConcurrentChildMap < Child > children ;
5554 protected Child noLabelsChild ;
5655
5756 /**
@@ -60,22 +59,39 @@ public abstract class SimpleCollector<Child> extends Collector {
6059 * Must be passed the same number of labels are were passed to {@link #labelNames}.
6160 */
6261 public Child labels (String ... labelValues ) {
63- if (labelValues .length != labelNames .size ()) {
62+ validateCount (labelValues .length );
63+ return children .labels (this , labelValues );
64+ }
65+
66+ public Child labels () {
67+ validateCount (0 );
68+ return noLabelsChild ;
69+ }
70+
71+ public Child labels (String lv1 ) {
72+ validateCount (1 );
73+ return children .labels (this , lv1 );
74+ }
75+
76+ public Child labels (String lv1 , String lv2 ) {
77+ validateCount (2 );
78+ return children .labels (this , lv1 , lv2 );
79+ }
80+
81+ public Child labels (String lv1 , String lv2 , String lv3 ) {
82+ validateCount (3 );
83+ return children .labels (this , lv1 , lv2 , lv3 );
84+ }
85+
86+ public Child labels (String lv1 , String lv2 , String lv3 , String lv4 ) {
87+ validateCount (4 );
88+ return children .labels (this , lv1 , lv2 , lv3 , lv4 );
89+ }
90+
91+ private void validateCount (int count ) {
92+ if (count != labelNames .size ()) {
6493 throw new IllegalArgumentException ("Incorrect number of labels." );
6594 }
66- for (String label : labelValues ) {
67- if (label == null ) {
68- throw new IllegalArgumentException ("Label cannot be null." );
69- }
70- }
71- List <String > key = Arrays .asList (labelValues );
72- Child c = children .get (key );
73- if (c != null ) {
74- return c ;
75- }
76- Child c2 = newChild ();
77- Child tmp = children .putIfAbsent (key , c2 );
78- return tmp == null ? c2 : tmp ;
7995 }
8096
8197 /**
@@ -84,7 +100,7 @@ public Child labels(String... labelValues) {
84100 * Any references to the Child are invalidated.
85101 */
86102 public void remove (String ... labelValues ) {
87- children .remove (Arrays . asList ( labelValues ) );
103+ children .remove (labelValues );
88104 initializeNoLabelsChild ();
89105 }
90106
@@ -104,7 +120,7 @@ public void clear() {
104120 protected void initializeNoLabelsChild () {
105121 // Initialize metric if it has no labels.
106122 if (labelNames .size () == 0 ) {
107- noLabelsChild = labels ();
123+ noLabelsChild = labels (new String [ 0 ] );
108124 }
109125 }
110126
@@ -132,10 +148,8 @@ protected void initializeNoLabelsChild() {
132148 * A metric should be either all callbacks, or none.
133149 */
134150 public <T extends Collector > T setChild (Child child , String ... labelValues ) {
135- if (labelValues .length != labelNames .size ()) {
136- throw new IllegalArgumentException ("Incorrect number of labels." );
137- }
138- children .put (Arrays .asList (labelValues ), child );
151+ validateCount (labelValues .length );
152+ children .setChild (child , labelValues );
139153 return (T )this ;
140154 }
141155
@@ -144,6 +158,11 @@ public <T extends Collector> T setChild(Child child, String... labelValues) {
144158 */
145159 protected abstract Child newChild ();
146160
161+ @ Override
162+ public Child newChild (String [] labels ) {
163+ return newChild ();
164+ }
165+
147166 protected List <MetricFamilySamples > familySamplesList (Collector .Type type , List <MetricFamilySamples .Sample > samples ) {
148167 MetricFamilySamples mfs = new MetricFamilySamples (fullname , type , help , samples );
149168 List <MetricFamilySamples > mfsList = new ArrayList <MetricFamilySamples >(1 );
@@ -152,6 +171,11 @@ protected List<MetricFamilySamples> familySamplesList(Collector.Type type, List<
152171 }
153172
154173 protected SimpleCollector (Builder b ) {
174+ try {
175+ children = (ConcurrentChildMap ) b .childMapClass .newInstance ();
176+ } catch (ReflectiveOperationException e ) {
177+ throw new RuntimeException ("Error instantiating child map class" , e );
178+ }
155179 if (b .name .isEmpty ()) throw new IllegalStateException ("Name hasn't been set." );
156180 String name = b .name ;
157181 if (!b .subsystem .isEmpty ()) {
@@ -187,6 +211,15 @@ public abstract static class Builder<B extends Builder<B, C>, C extends SimpleCo
187211 String [] labelNames = new String []{};
188212 // Some metrics require additional setup before the initialization can be done.
189213 boolean dontInitializeNoLabelsChild ;
214+ Class <? extends ConcurrentChildMap > childMapClass = ConcurrentChildHashMap .class ;
215+
216+ /**
217+ * Set a custom implementation for the internal labels-to-Child map.
218+ */
219+ public B childMap (Class <? extends ConcurrentChildMap > childMapClass ) {
220+ this .childMapClass = childMapClass ;
221+ return (B )this ;
222+ }
190223
191224 /**
192225 * Set the name of the metric. Required.
0 commit comments