Skip to content

Commit 3963d9f

Browse files
committed
support adding request-dependent tags to stream calls
1 parent 4b458cb commit 3963d9f

File tree

5 files changed

+239
-99
lines changed

5 files changed

+239
-99
lines changed

grpc-spring-boot-starter-demo/src/main/java/org/lognet/springboot/grpc/demo/GreeterService.java

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import lombok.extern.slf4j.Slf4j;
88
import org.lognet.springboot.grpc.GRpcService;
99
import org.lognet.springboot.grpc.security.GrpcSecurity;
10-
import org.springframework.beans.factory.annotation.Autowired;
1110
import org.springframework.security.access.annotation.Secured;
1211
import org.springframework.security.access.prepost.PostAuthorize;
1312
import org.springframework.security.access.prepost.PreAuthorize;
@@ -28,6 +27,27 @@ public void sayHello(GreeterOuterClass.HelloRequest request, StreamObserver<Gree
2827
log.info("Returning " +message);
2928
}
3029

30+
@Override public StreamObserver<GreeterOuterClass.HelloRequest> sayManyHellos(
31+
StreamObserver<GreeterOuterClass.HelloReply> responseObserver
32+
) {
33+
return new StreamObserver<GreeterOuterClass.HelloRequest>() {
34+
@Override public void onNext(GreeterOuterClass.HelloRequest request) {
35+
String message = "Hello " + request.getName();
36+
final GreeterOuterClass.HelloReply.Builder replyBuilder = GreeterOuterClass.HelloReply.newBuilder().setMessage(message);
37+
responseObserver.onNext(replyBuilder.build());
38+
log.info("Returning " + message);
39+
}
40+
41+
@Override
42+
public void onError(Throwable t) {}
43+
44+
@Override
45+
public void onCompleted() {
46+
responseObserver.onCompleted();
47+
}
48+
};
49+
}
50+
3151
@Override
3252
@Secured("SCOPE_profile")
3353
public void sayAuthHello(Empty request, StreamObserver<GreeterOuterClass.HelloReply> responseObserver) {

grpc-spring-boot-starter-demo/src/main/proto/greeter.proto

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ option java_package = "io.grpc.examples";
88
service Greeter {
99
// Sends a greeting
1010
rpc SayHello ( HelloRequest) returns ( HelloReply) {}
11+
rpc SayManyHellos (stream HelloRequest) returns (stream HelloReply) {}
1112
rpc SayAuthHello ( google.protobuf.Empty) returns ( HelloReply) {}
1213
rpc SayAuthOnlyHello ( google.protobuf.Empty) returns ( HelloReply) {}
1314
rpc SayPreAuthHello ( Person) returns ( Person) {}

grpc-spring-boot-starter-demo/src/test/java/org/lognet/springboot/grpc/GrpcMeterTest.java

Lines changed: 73 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,34 @@
11
package 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+
317
import io.grpc.Attributes;
418
import io.grpc.MethodDescriptor;
519
import io.grpc.Status;
620
import io.grpc.examples.GreeterGrpc;
721
import io.grpc.examples.GreeterOuterClass;
22+
import io.grpc.stub.StreamObserver;
823
import io.micrometer.core.instrument.MeterRegistry;
924
import io.micrometer.core.instrument.Tag;
25+
import io.micrometer.core.instrument.Tags;
1026
import io.micrometer.core.instrument.Timer;
11-
import io.micrometer.core.instrument.simple.SimpleConfig;
27+
import io.micrometer.core.instrument.search.MeterNotFoundException;
1228
import io.micrometer.prometheus.PrometheusConfig;
1329
import org.awaitility.Awaitility;
1430
import org.junit.Before;
31+
import org.junit.Test;
1532
import org.junit.runner.RunWith;
1633
import org.lognet.springboot.grpc.autoconfigure.metrics.RequestAwareGRpcMetricsTagsContributor;
1734
import org.lognet.springboot.grpc.context.LocalRunningGrpcPort;
@@ -26,17 +43,6 @@
2643
import org.springframework.test.context.ActiveProfiles;
2744
import 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

Comments
 (0)