Skip to content

Commit e950299

Browse files
committed
Add an end to end example for gRPC A66 metrics.
1 parent 8132882 commit e950299

File tree

13 files changed

+1880
-0
lines changed

13 files changed

+1880
-0
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
FROM eclipse-temurin:17-jdk-alpine
2+
COPY build/libs/backend.jar backend.jar
3+
ENTRYPOINT ["java","-jar","/backend.jar"]
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright 2023 The gRPC-GCP-Mobile Authors
2+
// All rights reserved.
3+
//
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+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
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+
plugins {
17+
id 'org.springframework.boot'
18+
}
19+
20+
dependencies {
21+
implementation project(':examples:grpc-observability:proto')
22+
implementation project(':grpc-server-spring-boot-starter')
23+
implementation 'org.springframework.boot:spring-boot-starter-actuator'
24+
implementation "org.springframework.boot:spring-boot-starter-web"
25+
implementation 'io.micrometer:micrometer-registry-prometheus'
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Copyright (c) 2016-2023 The gRPC-Spring Authors
3+
*
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+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
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+
17+
package net.devh.boot.grpc.examples.observability.backend;
18+
19+
import org.springframework.boot.SpringApplication;
20+
import org.springframework.boot.autoconfigure.SpringBootApplication;
21+
22+
@SpringBootApplication
23+
public class BackendApplication {
24+
25+
public static void main(String[] args) {
26+
SpringApplication.run(BackendApplication.class, args);
27+
}
28+
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
/*
2+
* Copyright (c) 2016-2023 The gRPC-Spring Authors
3+
*
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+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
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+
17+
package net.devh.boot.grpc.examples.observability.backend;
18+
19+
import java.util.concurrent.ThreadLocalRandom;
20+
21+
import io.grpc.Status;
22+
import io.grpc.stub.StreamObserver;
23+
import net.devh.boot.grpc.examples.observability.proto.BidiStreamingRequest;
24+
import net.devh.boot.grpc.examples.observability.proto.BidiStreamingResponse;
25+
import net.devh.boot.grpc.examples.observability.proto.ClientStreamingRequest;
26+
import net.devh.boot.grpc.examples.observability.proto.ClientStreamingResponse;
27+
import net.devh.boot.grpc.examples.observability.proto.ExampleServiceGrpc.ExampleServiceImplBase;
28+
import net.devh.boot.grpc.examples.observability.proto.ServerStreamingRequest;
29+
import net.devh.boot.grpc.examples.observability.proto.ServerStreamingResponse;
30+
import net.devh.boot.grpc.examples.observability.proto.UnaryRequest;
31+
import net.devh.boot.grpc.examples.observability.proto.UnaryResponse;
32+
import net.devh.boot.grpc.server.service.GrpcService;
33+
34+
@GrpcService
35+
public class ExampleServiceImpl extends ExampleServiceImplBase {
36+
37+
private boolean InjectError() {
38+
// We create ~5% error.
39+
return ThreadLocalRandom.current().nextInt(0, 99) >= 95;
40+
}
41+
42+
@Override
43+
public void unaryRpc(UnaryRequest request,
44+
StreamObserver<UnaryResponse> responseObserver) {
45+
if (InjectError()) {
46+
responseObserver.onError(Status.INTERNAL.asException());
47+
} else {
48+
responseObserver.onNext(UnaryResponse.newBuilder().setMessage(request.getMessage()).build());
49+
responseObserver.onCompleted();
50+
}
51+
}
52+
53+
@Override
54+
public StreamObserver<ClientStreamingRequest> clientStreamingRpc(
55+
StreamObserver<ClientStreamingResponse> responseObserver) {
56+
return new StreamObserver<>() {
57+
@Override
58+
public void onNext(ClientStreamingRequest value) {
59+
responseObserver.onNext(
60+
ClientStreamingResponse.newBuilder().setMessage(value.getMessage()).build());
61+
}
62+
63+
@Override
64+
public void onError(Throwable t) {
65+
responseObserver.onError(t);
66+
}
67+
68+
@Override
69+
public void onCompleted() {
70+
if (InjectError()) {
71+
responseObserver.onError(Status.INTERNAL.asException());
72+
} else {
73+
responseObserver.onCompleted();
74+
}
75+
}
76+
};
77+
}
78+
79+
@Override
80+
public void serverStreamingRpc(ServerStreamingRequest request,
81+
StreamObserver<ServerStreamingResponse> responseObserver) {
82+
if (InjectError()) {
83+
responseObserver.onError(Status.INTERNAL.asException());
84+
} else {
85+
responseObserver.onNext(
86+
ServerStreamingResponse.newBuilder().setMessage(request.getMessage()).build());
87+
responseObserver.onCompleted();
88+
}
89+
}
90+
91+
@Override
92+
public StreamObserver<BidiStreamingRequest> bidiStreamingRpc(
93+
StreamObserver<BidiStreamingResponse> responseObserver) {
94+
return new StreamObserver<>() {
95+
@Override
96+
public void onNext(BidiStreamingRequest value) {
97+
responseObserver.onNext(
98+
BidiStreamingResponse.newBuilder().setMessage(value.getMessage()).build());
99+
}
100+
101+
@Override
102+
public void onError(Throwable t) {
103+
responseObserver.onError(t);
104+
}
105+
106+
@Override
107+
public void onCompleted() {
108+
if (InjectError()) {
109+
responseObserver.onError(Status.INTERNAL.asException());
110+
} else {
111+
responseObserver.onCompleted();
112+
}
113+
}
114+
};
115+
}
116+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Port serves the monitoring traffic.
2+
server.port=8081
3+
# Expose the prometheus metrics via the monitoring port.
4+
# By default, expose on `/actuator/prometheus`.
5+
management.endpoints.web.exposure.include=prometheus
6+
# Port serves the gRPC traffic.
7+
grpc.server.port=9091
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
FROM eclipse-temurin:17-jdk-alpine
2+
COPY build/libs/frontend.jar frontend.jar
3+
ENTRYPOINT ["java","-jar","/frontend.jar"]
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright 2023 The gRPC-GCP-Mobile Authors
2+
// All rights reserved.
3+
//
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+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
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+
plugins {
17+
id 'org.springframework.boot'
18+
}
19+
20+
dependencies {
21+
implementation project(':examples:grpc-observability:proto')
22+
implementation project(':grpc-client-spring-boot-starter')
23+
implementation 'org.springframework.boot:spring-boot-starter-actuator'
24+
implementation "org.springframework.boot:spring-boot-starter-web"
25+
implementation 'io.micrometer:micrometer-registry-prometheus'
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
/*
2+
* Copyright (c) 2016-2023 The gRPC-Spring Authors
3+
*
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+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
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+
17+
package net.devh.boot.grpc.examples.observability.frontend;
18+
19+
import java.util.concurrent.ThreadLocalRandom;
20+
import java.util.logging.Logger;
21+
22+
import org.springframework.boot.CommandLineRunner;
23+
import org.springframework.boot.SpringApplication;
24+
import org.springframework.boot.autoconfigure.SpringBootApplication;
25+
26+
import io.grpc.Status;
27+
import io.grpc.stub.StreamObserver;
28+
import net.devh.boot.grpc.client.inject.GrpcClient;
29+
import net.devh.boot.grpc.examples.observability.proto.BidiStreamingRequest;
30+
import net.devh.boot.grpc.examples.observability.proto.BidiStreamingResponse;
31+
import net.devh.boot.grpc.examples.observability.proto.ClientStreamingRequest;
32+
import net.devh.boot.grpc.examples.observability.proto.ClientStreamingResponse;
33+
import net.devh.boot.grpc.examples.observability.proto.ExampleServiceGrpc.ExampleServiceStub;
34+
import net.devh.boot.grpc.examples.observability.proto.ServerStreamingRequest;
35+
import net.devh.boot.grpc.examples.observability.proto.ServerStreamingResponse;
36+
import net.devh.boot.grpc.examples.observability.proto.UnaryRequest;
37+
import net.devh.boot.grpc.examples.observability.proto.UnaryResponse;
38+
39+
@SpringBootApplication
40+
public class FrontendApplication implements CommandLineRunner {
41+
42+
private static final Logger LOGGER = Logger.getLogger(FrontendApplication.class.getName());
43+
44+
public static void main(String[] args) {
45+
SpringApplication.run(FrontendApplication.class, args);
46+
}
47+
48+
@GrpcClient("backend")
49+
private ExampleServiceStub stub;
50+
51+
private void CallUnaryRpc() {
52+
byte[] bytes = new byte[ThreadLocalRandom.current().nextInt(10240, 20480)];
53+
ThreadLocalRandom.current().nextBytes(bytes);
54+
UnaryRequest request = UnaryRequest.newBuilder().setMessage(new String(bytes)).build();
55+
stub.unaryRpc(request, new StreamObserver<>() {
56+
@Override
57+
public void onNext(UnaryResponse value) {}
58+
59+
@Override
60+
public void onError(Throwable t) {
61+
LOGGER.severe(Status.fromThrowable(t).toString());
62+
CallUnaryRpc();
63+
}
64+
65+
@Override
66+
public void onCompleted() {
67+
CallUnaryRpc();
68+
}
69+
});
70+
}
71+
72+
private void CallClientStreamingRpc() {
73+
byte[] bytes = new byte[ThreadLocalRandom.current().nextInt(10240, 20480)];
74+
ThreadLocalRandom.current().nextBytes(bytes);
75+
ClientStreamingRequest request = ClientStreamingRequest.newBuilder()
76+
.setMessage(new String(bytes)).build();
77+
StreamObserver<ClientStreamingRequest> requestStreamObserver = stub.clientStreamingRpc(
78+
new StreamObserver<>() {
79+
@Override
80+
public void onNext(ClientStreamingResponse value) {}
81+
82+
@Override
83+
public void onError(Throwable t) {
84+
CallClientStreamingRpc();
85+
}
86+
87+
@Override
88+
public void onCompleted() {
89+
CallClientStreamingRpc();
90+
}
91+
});
92+
requestStreamObserver.onNext(request);
93+
requestStreamObserver.onCompleted();
94+
}
95+
96+
private void CallServerStreamingRpc() {
97+
byte[] bytes = new byte[ThreadLocalRandom.current().nextInt(10240, 20480)];
98+
ThreadLocalRandom.current().nextBytes(bytes);
99+
ServerStreamingRequest request = ServerStreamingRequest.newBuilder()
100+
.setMessage(new String(bytes)).build();
101+
stub.serverStreamingRpc(request, new StreamObserver<>() {
102+
@Override
103+
public void onNext(ServerStreamingResponse value) {}
104+
105+
@Override
106+
public void onError(Throwable t) {
107+
CallServerStreamingRpc();
108+
}
109+
110+
@Override
111+
public void onCompleted() {
112+
CallServerStreamingRpc();
113+
}
114+
});
115+
}
116+
117+
private void CallBidStreamingRpc() {
118+
byte[] bytes = new byte[ThreadLocalRandom.current().nextInt(10240, 20480)];
119+
ThreadLocalRandom.current().nextBytes(bytes);
120+
BidiStreamingRequest request = BidiStreamingRequest.newBuilder()
121+
.setMessage(new String(bytes)).build();
122+
StreamObserver<BidiStreamingRequest> requestStreamObserver = stub.bidiStreamingRpc(
123+
new StreamObserver<>() {
124+
@Override
125+
public void onNext(BidiStreamingResponse value) {}
126+
127+
@Override
128+
public void onError(Throwable t) {
129+
CallBidStreamingRpc();
130+
}
131+
132+
@Override
133+
public void onCompleted() {
134+
CallBidStreamingRpc();
135+
}
136+
});
137+
requestStreamObserver.onNext(request);
138+
requestStreamObserver.onCompleted();
139+
}
140+
141+
@Override
142+
public void run(String... args) {
143+
CallUnaryRpc();
144+
CallServerStreamingRpc();
145+
CallClientStreamingRpc();
146+
CallBidStreamingRpc();
147+
}
148+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Port serves the monitoring traffic.
2+
server.port=8080
3+
# Expose the prometheus metrics via the monitoring port.
4+
# By default, expose on `/actuator/prometheus`.
5+
management.endpoints.web.exposure.include=prometheus,configprops,env,info
6+
management.endpoint.env.show-values=ALWAYS
7+
management.endpoint.configprops.show-values=ALWAYS
8+
# The backend service address, for local testing.
9+
grpc.client.backend.address=static://localhost:9091
10+
# Teh backend service address, for kubernetes.
11+
# grpc.client.backend.address=dns:///backend.default.svc.cluster.local:9091
12+
grpc.client.backend.negotiationType=PLAINTEXT

0 commit comments

Comments
 (0)