1
+ /**
2
+ * Copyright 2017 VMware, Inc.
3
+ * <p>
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * <p>
8
+ * https://www.apache.org/licenses/LICENSE-2.0
9
+ * <p>
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ package io .micrometer .prometheus ;
17
+
18
+ import io .micrometer .core .instrument .Meter ;
19
+ import io .micrometer .core .instrument .Tag ;
20
+ import io .micrometer .core .instrument .config .NamingConvention ;
21
+ import io .prometheus .client .Collector ;
22
+
23
+ import java .util .*;
24
+ import java .util .concurrent .ConcurrentHashMap ;
25
+ import java .util .stream .Stream ;
26
+
27
+ import static java .util .stream .Collectors .toList ;
28
+
29
+ /**
30
+ * {@link Collector} for Micrometer.
31
+ *
32
+ * @author Jon Schneider
33
+ * @author Johnny Lim
34
+ */
35
+ class MutatedMicrometerCollector extends Collector implements Collector .Describable {
36
+
37
+ static final class TagsHolder {
38
+ final List <String > keys ;
39
+ final List <String > values ;
40
+
41
+ private TagsHolder (List <String > keys , List <String > values ) {
42
+ this .keys = keys ;
43
+ this .values = values ;
44
+ }
45
+
46
+ static TagsHolder from (List <Tag > tags ) {
47
+ Objects .requireNonNull (tags , "tags" );
48
+
49
+ List <String > keys = new ArrayList <>(tags .size ());
50
+ List <String > values = new ArrayList <>(tags .size ());
51
+
52
+ for (Tag tag : tags ) {
53
+ keys .add (tag .getKey ());
54
+ values .add (tag .getValue ());
55
+ }
56
+
57
+ return new TagsHolder (
58
+ Collections .unmodifiableList (keys ),
59
+ Collections .unmodifiableList (values )
60
+ );
61
+ }
62
+
63
+ public List <String > getKeys () {
64
+ return keys ;
65
+ }
66
+
67
+ public List <String > getValues () {
68
+ return values ;
69
+ }
70
+
71
+ @ Override
72
+ public boolean equals (Object o ) {
73
+ if (this == o ) return true ;
74
+ if (o == null || getClass () != o .getClass ()) return false ;
75
+ TagsHolder that = (TagsHolder ) o ;
76
+ return keys .equals (that .keys ) && values .equals (that .values );
77
+ }
78
+
79
+ @ Override
80
+ public int hashCode () {
81
+ return Objects .hash (keys , values );
82
+ }
83
+ }
84
+
85
+ private final Meter .Id id ;
86
+ private final Map <TagsHolder , Child > children = new ConcurrentHashMap <>();
87
+ private final String conventionName ;
88
+ private final String help ;
89
+
90
+ public MutatedMicrometerCollector (Meter .Id id , NamingConvention convention , PrometheusConfig config ) {
91
+ this .id = id ;
92
+ this .conventionName = id .getConventionName (convention );
93
+ this .help = config .descriptions () ? Optional .ofNullable (id .getDescription ()).orElse (" " ) : " " ;
94
+ }
95
+
96
+ public void add (List <Tag > tags , Child child ) {
97
+ children .put (TagsHolder .from (tags ), child );
98
+ }
99
+
100
+ public void remove (List <Tag > tags ) {
101
+ children .remove (TagsHolder .from (tags ));
102
+ }
103
+
104
+ public boolean isEmpty () {
105
+ return children .isEmpty ();
106
+ }
107
+
108
+ @ Override
109
+ public List <MetricFamilySamples > collect () {
110
+ Map <String , Family > families = new HashMap <>();
111
+
112
+ for (Map .Entry <TagsHolder , Child > e : children .entrySet ()) {
113
+ TagsHolder tags = e .getKey ();
114
+ Child child = e .getValue ();
115
+
116
+ child .samples (conventionName , tags ).forEach (family -> {
117
+ families .compute (family .getConventionName (), (name , matchingFamily ) -> matchingFamily != null ?
118
+ matchingFamily .addSamples (family .samples ) : family );
119
+ });
120
+ }
121
+
122
+ return families .values ().stream ()
123
+ .map (family -> new MetricFamilySamples (family .conventionName , family .type , help , family .samples ))
124
+ .collect (toList ());
125
+ }
126
+
127
+ @ Override
128
+ public List <MetricFamilySamples > describe () {
129
+ switch (id .getType ()) {
130
+ case COUNTER :
131
+ return Collections .singletonList (
132
+ new MetricFamilySamples (conventionName , Type .COUNTER , help , Collections .emptyList ()));
133
+
134
+ case GAUGE :
135
+ return Collections .singletonList (
136
+ new MetricFamilySamples (conventionName , Type .GAUGE , help , Collections .emptyList ()));
137
+
138
+ case TIMER :
139
+ case DISTRIBUTION_SUMMARY :
140
+ return Arrays .asList (
141
+ new MetricFamilySamples (conventionName , Type .HISTOGRAM , help , Collections .emptyList ()),
142
+ new MetricFamilySamples (conventionName + "_max" , Type .GAUGE , help , Collections .emptyList ()));
143
+
144
+ case LONG_TASK_TIMER :
145
+ return Arrays .asList (
146
+ new MetricFamilySamples (conventionName , Type .HISTOGRAM , help , Collections .emptyList ()),
147
+ new MetricFamilySamples (conventionName , Type .UNKNOWN , help , Collections .emptyList ()));
148
+
149
+ default :
150
+ return Collections .singletonList (
151
+ new MetricFamilySamples (conventionName , Type .UNKNOWN , help , Collections .emptyList ()));
152
+ }
153
+ }
154
+
155
+ interface Child {
156
+ Stream <Family > samples (String conventionName , TagsHolder tags );
157
+ }
158
+
159
+ static class Family {
160
+ final Type type ;
161
+ final String conventionName ;
162
+ final List <MetricFamilySamples .Sample > samples = new ArrayList <>();
163
+
164
+ Family (Type type , String conventionName , MetricFamilySamples .Sample ... samples ) {
165
+ this .type = type ;
166
+ this .conventionName = conventionName ;
167
+ Collections .addAll (this .samples , samples );
168
+ }
169
+
170
+ Family (Type type , String conventionName , Stream <MetricFamilySamples .Sample > samples ) {
171
+ this .type = type ;
172
+ this .conventionName = conventionName ;
173
+ samples .forEach (this .samples ::add );
174
+ }
175
+
176
+ String getConventionName () {
177
+ return conventionName ;
178
+ }
179
+
180
+ Family addSamples (Collection <MetricFamilySamples .Sample > samples ) {
181
+ this .samples .addAll (samples );
182
+ return this ;
183
+ }
184
+ }
185
+ }
0 commit comments