16
16
17
17
package org .springframework .boot .actuate .autoconfigure .metrics ;
18
18
19
- import java .lang .reflect .Field ;
20
- import java .lang .reflect .Method ;
21
- import java .util .Collection ;
19
+ import java .util .ArrayList ;
22
20
import java .util .List ;
23
21
22
+ import io .micrometer .core .instrument .MeterRegistry ;
23
+ import io .micrometer .core .instrument .Tag ;
24
24
import io .micrometer .core .instrument .Tags ;
25
25
import io .micrometer .core .instrument .observation .MeterObservationHandler ;
26
+ import io .micrometer .core .instrument .observation .Observation ;
26
27
import io .micrometer .core .instrument .observation .Observation .Context ;
27
28
import io .micrometer .core .instrument .observation .Observation .GlobalTagsProvider ;
28
29
import io .micrometer .core .instrument .observation .ObservationHandler ;
29
30
import io .micrometer .core .instrument .observation .ObservationHandler .AllMatchingCompositeObservationHandler ;
30
- import io .micrometer .core .instrument .observation .ObservationHandler .CompositeObservationHandler ;
31
31
import io .micrometer .core .instrument .observation .ObservationHandler .FirstMatchingCompositeObservationHandler ;
32
32
import io .micrometer .core .instrument .observation .ObservationPredicate ;
33
33
import io .micrometer .core .instrument .observation .ObservationRegistry ;
34
- import io .micrometer .core .instrument .observation .ObservationRegistry .ObservationConfig ;
35
- import io .micrometer .core .instrument .observation .TimerObservationHandler ;
34
+ import io .micrometer .core .instrument .search .MeterNotFoundException ;
36
35
import io .micrometer .tracing .handler .TracingObservationHandler ;
37
36
import org .junit .jupiter .api .Test ;
38
37
42
41
import org .springframework .boot .test .context .runner .ApplicationContextRunner ;
43
42
import org .springframework .context .annotation .Bean ;
44
43
import org .springframework .context .annotation .Configuration ;
44
+ import org .springframework .context .annotation .Import ;
45
45
import org .springframework .core .annotation .Order ;
46
- import org .springframework .util .ReflectionUtils ;
47
46
48
47
import static org .assertj .core .api .Assertions .assertThat ;
48
+ import static org .assertj .core .api .Assertions .assertThatThrownBy ;
49
49
50
50
/**
51
51
* Tests for {@link ObservationAutoConfiguration}.
@@ -59,75 +59,57 @@ class ObservationAutoConfigurationTests {
59
59
.withConfiguration (AutoConfigurations .of (ObservationAutoConfiguration .class ));
60
60
61
61
@ Test
62
- void autoConfiguresTimerTimerObservationHandler () {
62
+ void autoConfiguresTimerObservationHandler () {
63
63
this .contextRunner .run ((context ) -> {
64
- ObservationRegistry observationRegistry = context .getBean (ObservationRegistry .class );
65
- List < ObservationHandler <?>> handlers = getObservationHandlers ( observationRegistry );
66
- assertThat ( handlers ). hasSize ( 1 );
67
- assertThat ( handlers . get ( 0 )). isInstanceOf ( TimerObservationHandler . class );
68
-
64
+ MeterRegistry meterRegistry = context .getBean (MeterRegistry .class );
65
+ Observation . start ( "test-observation" , meterRegistry ). stop ( );
66
+ // When a TimerObservationHandler is registered, every stopped Observation
67
+ // leads to a timer
68
+ assertThat ( meterRegistry . get ( "test-observation" ). timer (). count ()). isEqualTo ( 1 );
69
69
});
70
70
}
71
71
72
72
@ Test
73
73
void autoConfiguresObservationPredicates () {
74
74
this .contextRunner .withUserConfiguration (ObservationPredicates .class ).run ((context ) -> {
75
- ObservationRegistry observationRegistry = context .getBean (ObservationRegistry .class );
76
- assertThat (getObservationPredicates (observationRegistry )).hasSize (1 );
75
+ MeterRegistry meterRegistry = context .getBean (MeterRegistry .class );
76
+ // This is allowed by ObservationPredicates.customPredicate
77
+ Observation .start ("observation1" , meterRegistry ).start ().stop ();
78
+ // This isn't allowed by ObservationPredicates.customPredicate
79
+ Observation .start ("observation2" , meterRegistry ).start ().stop ();
80
+ assertThat (meterRegistry .get ("observation1" ).timer ().count ()).isEqualTo (1 );
81
+ assertThatThrownBy (() -> meterRegistry .get ("observation2" ).timer ())
82
+ .isInstanceOf (MeterNotFoundException .class );
77
83
});
78
84
}
79
85
80
86
@ Test
81
87
void autoConfiguresGlobalTagsProvider () {
82
88
this .contextRunner .withUserConfiguration (GlobalTagsProviders .class ).run ((context ) -> {
83
89
ObservationRegistry observationRegistry = context .getBean (ObservationRegistry .class );
84
- assertThat (getTagsProviders (observationRegistry )).hasSize (1 );
90
+ Context micrometerContext = new Context ();
91
+ Observation .start ("test-observation" , micrometerContext , observationRegistry ).stop ();
92
+ assertThat (micrometerContext .getAllTags ()).containsExactly (Tag .of ("tag1" , "value1" ));
85
93
});
86
94
}
87
95
88
96
@ Test
89
- @ SuppressWarnings ("rawtypes" )
90
97
void autoConfiguresObservationHandler () {
91
98
this .contextRunner .withUserConfiguration (ObservationHandlers .class ).run ((context ) -> {
92
99
ObservationRegistry observationRegistry = context .getBean (ObservationRegistry .class );
93
- List <ObservationHandler <?>> handlers = getObservationHandlers (observationRegistry );
94
- assertThat (handlers ).hasSize (5 );
95
- assertThat (handlers .get (0 )).isInstanceOf (TimerObservationHandler .class );
96
- assertThat (handlers .get (1 )).isInstanceOf (CustomObservationHandler .class );
97
- assertThat (handlers .get (2 )).isInstanceOf (FirstMatchingCompositeObservationHandler .class );
98
- assertThat (handlers .get (3 )).isInstanceOf (AllMatchingCompositeObservationHandler .class );
99
- // CustomMeterObservationHandlers get wrapped into a
100
- // FirstMatchingCompositeObservationHandler
101
- assertThat (handlers .get (4 )).isInstanceOf (FirstMatchingCompositeObservationHandler .class );
102
- List <ObservationHandler > containedHandlers = ((CompositeObservationHandler ) handlers .get (4 )).getHandlers ();
103
- assertThat (containedHandlers ).hasSize (2 );
104
- assertThat (containedHandlers .get (0 )).isInstanceOf (CustomMeterObservationHandler .class );
105
- assertThat (containedHandlers .get (1 )).isInstanceOf (CustomMeterObservationHandler .class );
100
+ List <ObservationHandler <?>> handlers = context .getBean (CalledHandlers .class ).getCalledHandlers ();
101
+ Observation .start ("test-observation" , observationRegistry );
102
+ assertThat (handlers ).hasSize (2 );
103
+ // Regular handlers are registered first
104
+ assertThat (handlers .get (0 )).isInstanceOf (CustomObservationHandler .class );
105
+ // Multiple MeterObservationHandler are wrapped in
106
+ // FirstMatchingCompositeObservationHandler, which calls only the first one
107
+ assertThat (handlers .get (1 )).isInstanceOf (CustomMeterObservationHandler .class );
108
+ assertThat (((CustomMeterObservationHandler ) handlers .get (1 )).getName ())
109
+ .isEqualTo ("customMeterObservationHandler1" );
106
110
});
107
111
}
108
112
109
- @ SuppressWarnings ("unchecked" )
110
- private List <ObservationPredicate > getObservationPredicates (ObservationRegistry observationRegistry ) {
111
- Field field = ReflectionUtils .findField (ObservationConfig .class , "observationPredicates" );
112
- ReflectionUtils .makeAccessible (field );
113
- return (List <ObservationPredicate >) ReflectionUtils .getField (field , observationRegistry .observationConfig ());
114
- }
115
-
116
- @ SuppressWarnings ("unchecked" )
117
- private Collection <GlobalTagsProvider <?>> getTagsProviders (ObservationRegistry registry ) {
118
- Method method = ReflectionUtils .findMethod (ObservationConfig .class , "getTagsProviders" );
119
- ReflectionUtils .makeAccessible (method );
120
- return (Collection <GlobalTagsProvider <?>>) ReflectionUtils .invokeMethod (method , registry .observationConfig ());
121
- }
122
-
123
- @ SuppressWarnings ("unchecked" )
124
- private List <ObservationHandler <?>> getObservationHandlers (ObservationRegistry registry ) {
125
- Method method = ReflectionUtils .findMethod (ObservationConfig .class , "getObservationHandlers" );
126
- ReflectionUtils .makeAccessible (method );
127
- return List .copyOf (
128
- (Collection <ObservationHandler <?>>) ReflectionUtils .invokeMethod (method , registry .observationConfig ()));
129
- }
130
-
131
113
@ Configuration (proxyBeanMethods = false )
132
114
static class ObservationPredicates {
133
115
@@ -159,6 +141,17 @@ public Tags getLowCardinalityTags(Context context) {
159
141
}
160
142
161
143
@ Configuration (proxyBeanMethods = false )
144
+ static class CalledHandlersConfiguration {
145
+
146
+ @ Bean
147
+ CalledHandlers calledHandlers () {
148
+ return new CalledHandlers ();
149
+ }
150
+
151
+ }
152
+
153
+ @ Configuration (proxyBeanMethods = false )
154
+ @ Import (CalledHandlersConfiguration .class )
162
155
static class ObservationHandlers {
163
156
164
157
@ Bean
@@ -175,26 +168,51 @@ FirstMatchingCompositeObservationHandler customFirstMatchingCompositeObservation
175
168
176
169
@ Bean
177
170
@ Order (2 )
178
- ObservationHandler <Context > customObservationHandler () {
179
- return new CustomObservationHandler ();
171
+ ObservationHandler <Context > customObservationHandler (CalledHandlers calledHandlers ) {
172
+ return new CustomObservationHandler (calledHandlers );
180
173
}
181
174
182
175
@ Bean
183
176
@ Order (1 )
184
- MeterObservationHandler <Context > customMeterObservationHandler2 () {
185
- return new CustomMeterObservationHandler ();
177
+ MeterObservationHandler <Context > customMeterObservationHandler2 (CalledHandlers calledHandlers ) {
178
+ return new CustomMeterObservationHandler ("customMeterObservationHandler2" , calledHandlers );
186
179
}
187
180
188
181
@ Bean
189
182
@ Order (0 )
190
- MeterObservationHandler <Context > customMeterObservationHandler1 () {
191
- return new CustomMeterObservationHandler ();
183
+ MeterObservationHandler <Context > customMeterObservationHandler1 (CalledHandlers calledHandlers ) {
184
+ return new CustomMeterObservationHandler ("customMeterObservationHandler1" , calledHandlers );
185
+ }
186
+
187
+ }
188
+
189
+ static class CalledHandlers {
190
+
191
+ private final List <ObservationHandler <?>> calledHandlers = new ArrayList <>();
192
+
193
+ void onCalled (ObservationHandler <?> handler ) {
194
+ this .calledHandlers .add (handler );
195
+ }
196
+
197
+ List <ObservationHandler <?>> getCalledHandlers () {
198
+ return this .calledHandlers ;
192
199
}
193
200
194
201
}
195
202
196
203
static class CustomObservationHandler implements ObservationHandler <Context > {
197
204
205
+ private final CalledHandlers calledHandlers ;
206
+
207
+ CustomObservationHandler (CalledHandlers calledHandlers ) {
208
+ this .calledHandlers = calledHandlers ;
209
+ }
210
+
211
+ @ Override
212
+ public void onStart (Context context ) {
213
+ this .calledHandlers .onCalled (this );
214
+ }
215
+
198
216
@ Override
199
217
public boolean supportsContext (Context context ) {
200
218
return true ;
@@ -204,6 +222,24 @@ public boolean supportsContext(Context context) {
204
222
205
223
static class CustomMeterObservationHandler implements MeterObservationHandler <Context > {
206
224
225
+ private final CalledHandlers calledHandlers ;
226
+
227
+ private final String name ;
228
+
229
+ CustomMeterObservationHandler (String name , CalledHandlers calledHandlers ) {
230
+ this .name = name ;
231
+ this .calledHandlers = calledHandlers ;
232
+ }
233
+
234
+ String getName () {
235
+ return this .name ;
236
+ }
237
+
238
+ @ Override
239
+ public void onStart (Context context ) {
240
+ this .calledHandlers .onCalled (this );
241
+ }
242
+
207
243
@ Override
208
244
public boolean supportsContext (Context context ) {
209
245
return true ;
0 commit comments