• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  * Copyright 2021 gRPC authors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 // Explicitly define HAVE_ABSEIL to avoid conflict with OTel's Abseil
20 // version. Refer
21 // https://github.com/open-telemetry/opentelemetry-cpp/issues/1042.
22 #ifndef HAVE_ABSEIL
23 #define HAVE_ABSEIL
24 #endif
25 
26 #include <grpcpp/ext/otel_plugin.h>
27 #include <grpcpp/grpcpp.h>
28 
29 #include <condition_variable>
30 #include <mutex>
31 #include <string>
32 
33 #include "absl/flags/flag.h"
34 #include "absl/flags/parse.h"
35 #include "opentelemetry/exporters/prometheus/exporter_factory.h"
36 #include "opentelemetry/exporters/prometheus/exporter_options.h"
37 #include "opentelemetry/sdk/metrics/meter_provider.h"
38 
39 #ifdef BAZEL_BUILD
40 #include "examples/cpp/otel/codelab/util.h"
41 #include "examples/protos/helloworld.grpc.pb.h"
42 #else
43 #include "helloworld.grpc.pb.h"
44 #include "util.h"
45 #endif
46 
47 ABSL_FLAG(std::string, target, "localhost:50051", "Server address");
48 ABSL_FLAG(std::string, prometheus_endpoint, "localhost:9465",
49           "Prometheus exporter endpoint");
50 
51 namespace {
52 
53 using grpc::Channel;
54 using grpc::ClientContext;
55 using grpc::Status;
56 using helloworld::Greeter;
57 using helloworld::HelloReply;
58 using helloworld::HelloRequest;
59 
60 class GreeterClient {
61  public:
GreeterClient(std::shared_ptr<Channel> channel)62   GreeterClient(std::shared_ptr<Channel> channel)
63       : stub_(Greeter::NewStub(channel)) {}
64 
65   // Assembles the client's payload, sends it and presents the response back
66   // from the server.
SayHello(const std::string & user)67   std::string SayHello(const std::string& user) {
68     // Data we are sending to the server.
69     HelloRequest request;
70     request.set_name(user);
71 
72     // Container for the data we expect from the server.
73     HelloReply reply;
74 
75     // Context for the client. It could be used to convey extra information to
76     // the server and/or tweak certain RPC behaviors.
77     ClientContext context;
78 
79     // The actual RPC.
80     std::mutex mu;
81     std::condition_variable cv;
82     bool done = false;
83     Status status;
84     stub_->async()->SayHello(&context, &request, &reply,
85                              [&mu, &cv, &done, &status](Status s) {
86                                status = std::move(s);
87                                std::lock_guard<std::mutex> lock(mu);
88                                done = true;
89                                cv.notify_one();
90                              });
91 
92     std::unique_lock<std::mutex> lock(mu);
93     while (!done) {
94       cv.wait(lock);
95     }
96 
97     // Act upon its status.
98     if (status.ok()) {
99       return reply.message();
100     } else {
101       std::cout << status.error_code() << ": " << status.error_message()
102                 << std::endl;
103       return "RPC failed";
104     }
105   }
106 
107  private:
108   std::unique_ptr<Greeter::Stub> stub_;
109 };
110 
RunClient(const std::string & target_str)111 void RunClient(const std::string& target_str) {
112   // Instantiate the client. It requires a channel, out of which the actual RPCs
113   // are created. This channel models a connection to an endpoint specified by
114   // the argument "--target=" which is the only expected argument.
115   grpc::ChannelArguments args;
116   // Continuously send RPCs every second.
117   while (true) {
118     GreeterClient greeter(grpc::CreateCustomChannel(
119         target_str, grpc::InsecureChannelCredentials(), args));
120     std::string user("world");
121     std::string reply = greeter.SayHello(user);
122     std::cout << "Greeter received: " << reply << std::endl;
123     std::this_thread::sleep_for(std::chrono::seconds(1));
124   }
125 }
126 
127 }  // namespace
128 
main(int argc,char ** argv)129 int main(int argc, char** argv) {
130   absl::ParseCommandLine(argc, argv);
131   // Register a global gRPC OpenTelemetry plugin configured with a prometheus
132   // exporter.
133   opentelemetry::exporter::metrics::PrometheusExporterOptions opts;
134   opts.url = absl::GetFlag(FLAGS_prometheus_endpoint);
135   auto prometheus_exporter =
136       opentelemetry::exporter::metrics::PrometheusExporterFactory::Create(opts);
137   auto meter_provider =
138       std::make_shared<opentelemetry::sdk::metrics::MeterProvider>();
139   // The default histogram boundaries are not granular enough for RPCs. Override
140   // the "grpc.client.attempt.duration" view as recommended by
141   // https://github.com/grpc/proposal/blob/master/A66-otel-stats.md.
142   AddLatencyView(meter_provider.get(), "grpc.client.attempt.duration", "s");
143   meter_provider->AddMetricReader(std::move(prometheus_exporter));
144   auto status = grpc::OpenTelemetryPluginBuilder()
145                     .SetMeterProvider(std::move(meter_provider))
146                     .BuildAndRegisterGlobal();
147   if (!status.ok()) {
148     std::cerr << "Failed to register gRPC OpenTelemetry Plugin: "
149               << status.ToString() << std::endl;
150     return static_cast<int>(status.code());
151   }
152 
153   // Continuously send RPCs.
154   RunClient(absl::GetFlag(FLAGS_target));
155 
156   return 0;
157 }
158