11package org .lognet .springboot .grpc ;
22
3+ import static io .grpc .MethodDescriptor .MethodType .BIDI_STREAMING ;
4+ import static org .hamcrest .MatcherAssert .assertThat ;
5+ import static org .hamcrest .Matchers .containsString ;
6+ import static org .hamcrest .Matchers .greaterThan ;
7+ import static org .hamcrest .Matchers .is ;
8+ import static org .hamcrest .Matchers .notNullValue ;
9+ import static org .springframework .boot .test .context .SpringBootTest .WebEnvironment .NONE ;
10+
11+ import java .time .Duration ;
12+ import java .util .Arrays ;
13+ import java .util .Collections ;
14+ import java .util .Objects ;
15+ import java .util .concurrent .TimeUnit ;
16+
317import io .grpc .Attributes ;
418import io .grpc .MethodDescriptor ;
519import io .grpc .Status ;
620import io .grpc .examples .GreeterGrpc ;
721import io .grpc .examples .GreeterOuterClass ;
22+ import io .grpc .stub .StreamObserver ;
823import io .micrometer .core .instrument .MeterRegistry ;
924import io .micrometer .core .instrument .Tag ;
25+ import io .micrometer .core .instrument .Tags ;
1026import io .micrometer .core .instrument .Timer ;
11- import io .micrometer .core .instrument .simple . SimpleConfig ;
27+ import io .micrometer .core .instrument .search . MeterNotFoundException ;
1228import io .micrometer .prometheus .PrometheusConfig ;
1329import org .awaitility .Awaitility ;
1430import org .junit .Before ;
31+ import org .junit .Test ;
1532import org .junit .runner .RunWith ;
1633import org .lognet .springboot .grpc .autoconfigure .metrics .RequestAwareGRpcMetricsTagsContributor ;
1734import org .lognet .springboot .grpc .context .LocalRunningGrpcPort ;
2643import org .springframework .test .context .ActiveProfiles ;
2744import org .springframework .test .context .junit4 .SpringRunner ;
2845
29- import java .time .Duration ;
30- import java .util .Collections ;
31- import java .util .concurrent .TimeUnit ;
32-
33- import static org .hamcrest .MatcherAssert .assertThat ;
34- import static org .hamcrest .Matchers .containsString ;
35- import static org .hamcrest .Matchers .greaterThan ;
36- import static org .hamcrest .Matchers .is ;
37- import static org .hamcrest .Matchers .notNullValue ;
38- import static org .springframework .boot .test .context .SpringBootTest .WebEnvironment .NONE ;
39-
4046@ RunWith (SpringRunner .class )
4147@ SpringBootTest (classes = {DemoApp .class }, webEnvironment = NONE , properties = {"grpc.port=0" })
4248@ ActiveProfiles ("measure" )
@@ -48,7 +54,7 @@ static class Config{
4854 public RequestAwareGRpcMetricsTagsContributor <GreeterOuterClass .HelloRequest > helloContributor (){
4955 return new RequestAwareGRpcMetricsTagsContributor <GreeterOuterClass .HelloRequest >(GreeterOuterClass .HelloRequest .class ) {
5056 @ Override
51- public Iterable <Tag > getTags (GreeterOuterClass .HelloRequest request , MethodDescriptor <?, ?> methodDescriptor , Attributes attributes ) {
57+ public Iterable <Tag > addTags (GreeterOuterClass .HelloRequest request , MethodDescriptor <?, ?> methodDescriptor , Attributes attributes , Tags tags ) {
5258 return Collections .singletonList (Tag .of ("hello" ,request .getName ()));
5359 }
5460
@@ -62,7 +68,7 @@ public Iterable<Tag> getTags(Status status, MethodDescriptor<?, ?> methodDescrip
6268 public RequestAwareGRpcMetricsTagsContributor <GreeterOuterClass .Person > shouldNotBeInvoked (){
6369 return new RequestAwareGRpcMetricsTagsContributor <GreeterOuterClass .Person >(GreeterOuterClass .Person .class ) {
6470 @ Override
65- public Iterable <Tag > getTags (GreeterOuterClass .Person request , MethodDescriptor <?, ?> methodDescriptor , Attributes attributes ) {
71+ public Iterable <Tag > addTags (GreeterOuterClass .Person request , MethodDescriptor <?, ?> methodDescriptor , Attributes attributes , Tags tags ) {
6672 return Collections .emptyList ();
6773 }
6874
@@ -72,6 +78,26 @@ public Iterable<Tag> getTags(Status status, MethodDescriptor<?, ?> methodDescrip
7278 }
7379 };
7480 }
81+
82+ @ Bean
83+ public RequestAwareGRpcMetricsTagsContributor <GreeterOuterClass .HelloRequest > multiHelloContributor () {
84+ return new RequestAwareGRpcMetricsTagsContributor <GreeterOuterClass .HelloRequest >(GreeterOuterClass .HelloRequest .class , BIDI_STREAMING ) {
85+ @ Override
86+ public Tags addTags (GreeterOuterClass .HelloRequest request , MethodDescriptor <?, ?> methodDescriptor , Attributes attributes , Tags existingTags ) {
87+ String existingTag = existingTags .stream ()
88+ .filter (tag -> tag .getKey ().equals ("many-hellos" ))
89+ .findAny ()
90+ .map (Tag ::getValue )
91+ .orElse ("" );
92+ return Tags .of ("many-hellos" , existingTag .isEmpty () ? request .getName () : existingTag + ", " + request .getName ());
93+ }
94+
95+ @ Override
96+ public Iterable <Tag > getTags (Status status , MethodDescriptor <?, ?> methodDescriptor , Attributes attributes ) {
97+ return Collections .singletonList (Tag .of ("endTag" , status .getCode ().name ()));
98+ }
99+ };
100+ }
75101 }
76102
77103 @ SpyBean
@@ -131,10 +157,41 @@ protected void afterGreeting() {
131157
132158 Mockito .verify (shouldNotBeInvoked ,Mockito .times (1 )).getTags (Mockito .any (Status .class ),Mockito .any (),Mockito .any ());
133159 Mockito .verify (shouldNotBeInvoked ,Mockito .never ()).getTags (Mockito .any (GreeterOuterClass .Person .class ),Mockito .any (),Mockito .any ());
160+ Mockito .verify (shouldNotBeInvoked , Mockito .never ())
161+ .addTags (Mockito .any (GreeterOuterClass .Person .class ), Mockito .any (), Mockito .any (), Mockito .any ());
162+ }
134163
164+ @ Test
165+ public void tagsForStream () {
166+ final GreeterGrpc .GreeterStub greeterFutureStub = GreeterGrpc .newStub (selectedChanel );
167+ io .grpc .stub .StreamObserver <GreeterOuterClass .HelloRequest > helloInput =
168+ greeterFutureStub .sayManyHellos (new StreamObserver <GreeterOuterClass .HelloReply >() {
169+ @ Override
170+ public void onNext (GreeterOuterClass .HelloReply value ) {}
135171
172+ @ Override
173+ public void onError (Throwable t ) {}
136174
137-
138-
175+ @ Override
176+ public void onCompleted () {}
177+ });
178+ Arrays .asList ("a" , "b" , "c" , "d" ).stream ()
179+ .map (name -> GreeterOuterClass .HelloRequest .newBuilder ().setName (name ).build ())
180+ .forEach (helloInput ::onNext );
181+ helloInput .onCompleted ();
182+
183+ final Timer timer = Awaitility
184+ .waitAtMost (Duration .ofMillis (registryConfig .step ().toMillis () * 2 ))
185+ .ignoreExceptionsInstanceOf (MeterNotFoundException .class )
186+ .until (
187+ () -> registry .get ("grpc.server.calls" )
188+ .tags ("method" , "Greeter/SayManyHellos" )
189+ .timer (),
190+ Objects ::nonNull
191+ );
192+
193+ assertThat (timer .totalTime (TimeUnit .MILLISECONDS ), greaterThan (0d ));
194+ assertThat (timer .getId ().getTag ("many-hellos" ), is ("a, b, c, d" ));
195+ assertThat (timer .getId ().getTag ("endTag" ), is ("OK" ));
139196 }
140197}
0 commit comments