17
17
package org .springframework .boot .actuate .metrics ;
18
18
19
19
import java .util .ArrayList ;
20
- import java .util .Collection ;
21
20
import java .util .Collections ;
22
21
import java .util .HashMap ;
23
- import java .util .HashSet ;
22
+ import java .util .LinkedHashMap ;
23
+ import java .util .LinkedHashSet ;
24
24
import java .util .List ;
25
25
import java .util .Map ;
26
26
import java .util .Set ;
27
+ import java .util .function .BiFunction ;
27
28
import java .util .stream .Collectors ;
28
- import java .util .stream .Stream ;
29
29
30
- import io .micrometer .core .instrument .Measurement ;
31
30
import io .micrometer .core .instrument .Meter ;
32
31
import io .micrometer .core .instrument .MeterRegistry ;
33
32
import io .micrometer .core .instrument .Statistic ;
44
43
* An {@link Endpoint} for exposing the metrics held by a {@link MeterRegistry}.
45
44
*
46
45
* @author Jon Schneider
46
+ * @author Phillip Webb
47
47
* @since 2.0.0
48
48
*/
49
49
@ Endpoint (id = "metrics" )
@@ -57,24 +57,22 @@ public MetricsEndpoint(MeterRegistry registry) {
57
57
58
58
@ ReadOperation
59
59
public ListNamesResponse listNames () {
60
- return new ListNamesResponse (recurseListNames (this .registry ));
60
+ Set <String > names = new LinkedHashSet <>();
61
+ collectNames (names , this .registry );
62
+ return new ListNamesResponse (names );
61
63
}
62
64
63
- private Set <String > recurseListNames (MeterRegistry registry ) {
64
- Set <String > names = new HashSet <>();
65
+ private void collectNames (Set <String > names , MeterRegistry registry ) {
65
66
if (registry instanceof CompositeMeterRegistry ) {
66
- for (MeterRegistry compositeMember : ((CompositeMeterRegistry ) registry )
67
- .getRegistries ()) {
68
- names .addAll (recurseListNames (compositeMember ));
69
- }
67
+ ((CompositeMeterRegistry ) registry ).getRegistries ()
68
+ .forEach ((member ) -> collectNames (names , member ));
70
69
}
71
70
else {
72
- registry .getMeters ().stream ().map (this ::getMeterIdName ).forEach (names ::add );
71
+ registry .getMeters ().stream ().map (this ::getName ).forEach (names ::add );
73
72
}
74
- return names ;
75
73
}
76
74
77
- private String getMeterIdName (Meter meter ) {
75
+ private String getName (Meter meter ) {
78
76
return meter .getId ().getName ();
79
77
}
80
78
@@ -84,59 +82,73 @@ public MetricResponse metric(@Selector String requiredMetricName,
84
82
Assert .isTrue (tag == null || tag .stream ().allMatch ((t ) -> t .contains (":" )),
85
83
"Each tag parameter must be in the form key:value" );
86
84
List <Tag > tags = parseTags (tag );
87
- Collection <Meter > meters = recurseFindMeter (this .registry , requiredMetricName , tags );
85
+ List <Meter > meters = new ArrayList <>();
86
+ collectMeters (meters , this .registry , requiredMetricName , tags );
88
87
if (meters .isEmpty ()) {
89
88
return null ;
90
89
}
91
-
92
- Map <Statistic , Double > samples = new HashMap <>();
93
- Map <String , List <String >> availableTags = new HashMap <>();
94
-
95
- for (Meter meter : meters ) {
96
- for (Measurement ms : meter .measure ()) {
97
- samples .merge (ms .getStatistic (), ms .getValue (), Double ::sum );
98
- }
99
- for (Tag availableTag : meter .getId ().getTags ()) {
100
- availableTags .merge (availableTag .getKey (),
101
- Collections .singletonList (availableTag .getValue ()),
102
- (t1 , t2 ) -> Stream .concat (t1 .stream (), t2 .stream ())
103
- .collect (Collectors .toList ()));
104
- }
105
- }
106
-
90
+ Map <Statistic , Double > samples = getSamples (meters );
91
+ Map <String , List <String >> availableTags = getAvailableTags (meters );
107
92
tags .forEach ((t ) -> availableTags .remove (t .getKey ()));
108
-
109
93
return new MetricResponse (requiredMetricName ,
110
- samples .entrySet ().stream ()
111
- .map ((sample ) -> new MetricResponse .Sample (sample .getKey (),
112
- sample .getValue ()))
113
- .collect (Collectors .toList ()),
114
- availableTags .entrySet ().stream ()
115
- .map ((tagValues ) -> new MetricResponse .AvailableTag (
116
- tagValues .getKey (), tagValues .getValue ()))
117
- .collect (Collectors .toList ()));
94
+ asList (samples , MetricResponse .Sample ::new ),
95
+ asList (availableTags , MetricResponse .AvailableTag ::new ));
118
96
}
119
97
120
- private Collection <Meter > recurseFindMeter (MeterRegistry registry , String name ,
98
+ private List <Tag > parseTags (List <String > tags ) {
99
+ return tags == null ? Collections .emptyList () : tags .stream ().map ((t ) -> {
100
+ String [] tagParts = t .split (":" , 2 );
101
+ return Tag .of (tagParts [0 ], tagParts [1 ]);
102
+ }).collect (Collectors .toList ());
103
+ }
104
+
105
+ private void collectMeters (List <Meter > meters , MeterRegistry registry , String name ,
121
106
Iterable <Tag > tags ) {
122
- Collection <Meter > meters = new ArrayList <>();
123
107
if (registry instanceof CompositeMeterRegistry ) {
124
- for (MeterRegistry compositeMember : ((CompositeMeterRegistry ) registry )
125
- .getRegistries ()) {
126
- meters .addAll (recurseFindMeter (compositeMember , name , tags ));
127
- }
108
+ ((CompositeMeterRegistry ) registry ).getRegistries ()
109
+ .forEach ((member ) -> collectMeters (meters , member , name , tags ));
128
110
}
129
111
else {
130
112
meters .addAll (registry .find (name ).tags (tags ).meters ());
131
113
}
132
- return meters ;
133
114
}
134
115
135
- private List <Tag > parseTags (List <String > tags ) {
136
- return tags == null ? Collections .emptyList () : tags .stream ().map ((t ) -> {
137
- String [] tagParts = t .split (":" , 2 );
138
- return Tag .of (tagParts [0 ], tagParts [1 ]);
139
- }).collect (Collectors .toList ());
116
+ private Map <Statistic , Double > getSamples (List <Meter > meters ) {
117
+ Map <Statistic , Double > samples = new LinkedHashMap <>();
118
+ meters .forEach ((meter ) -> mergeMeasurements (samples , meter ));
119
+ return samples ;
120
+ }
121
+
122
+ private void mergeMeasurements (Map <Statistic , Double > samples , Meter meter ) {
123
+ meter .measure ().forEach ((measurement ) -> samples .merge (measurement .getStatistic (),
124
+ measurement .getValue (), Double ::sum ));
125
+ }
126
+
127
+ private Map <String , List <String >> getAvailableTags (List <Meter > meters ) {
128
+ Map <String , List <String >> availableTags = new HashMap <>();
129
+ meters .forEach ((meter ) -> mergeAvailableTags (availableTags , meter ));
130
+ return availableTags ;
131
+ }
132
+
133
+ private void mergeAvailableTags (Map <String , List <String >> availableTags ,
134
+ Meter meter ) {
135
+ meter .getId ().getTags ().forEach ((tag ) -> {
136
+ List <String > value = Collections .singletonList (tag .getValue ());
137
+ availableTags .merge (tag .getKey (), value , this ::merge );
138
+ });
139
+ }
140
+
141
+ private <T > List <T > merge (List <T > list1 , List <T > list2 ) {
142
+ List <T > result = new ArrayList <>(list1 .size () + list2 .size ());
143
+ result .addAll (list1 );
144
+ result .addAll (list2 );
145
+ return result ;
146
+ }
147
+
148
+ private <K , V , T > List <T > asList (Map <K , V > map , BiFunction <K , V , T > mapper ) {
149
+ return map .entrySet ().stream ()
150
+ .map ((entry ) -> mapper .apply (entry .getKey (), entry .getValue ()))
151
+ .collect (Collectors .toCollection (ArrayList ::new ));
140
152
}
141
153
142
154
/**
@@ -235,6 +247,8 @@ public String toString() {
235
247
return "MeasurementSample{" + "statistic=" + this .statistic + ", value="
236
248
+ this .value + '}' ;
237
249
}
250
+
238
251
}
252
+
239
253
}
240
254
}
0 commit comments