diff options
author | Yash Tibrewal <yashkt@google.com> | 2023-03-27 12:59:45 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-03-27 12:59:45 -0700 |
commit | 1293ee8286be2be54997b5d9f64035db74c5fcf7 (patch) | |
tree | 63de37ce9853b2459de9a612c64fefc894d4d0d0 /examples | |
parent | 7bd9267f325939623d573e1dca43d77b090fdfa7 (diff) | |
download | grpc-grpc-1293ee8286be2be54997b5d9f64035db74c5fcf7.tar.gz |
Gcp Observability: Add example (#32710)
Adds a simple hello-world example for GCP Observability purposes along
with a README.
The microservices observability user guide is not yet up, but this still
refers to it anyway.
<!--
If you know who should review your pull request, please assign it to
that
person, otherwise the pull request would get assigned randomly.
If your pull request is for a specific language, please add the
appropriate
lang label.
-->
Diffstat (limited to 'examples')
7 files changed, 357 insertions, 0 deletions
diff --git a/examples/cpp/gcp_observability/helloworld/.gitignore b/examples/cpp/gcp_observability/helloworld/.gitignore new file mode 100644 index 0000000000..039149b025 --- /dev/null +++ b/examples/cpp/gcp_observability/helloworld/.gitignore @@ -0,0 +1,8 @@ +*.o +*.pb.cc +*.pb.h +greeter_client +greeter_server +greeter_async_client +greeter_async_client2 +greeter_async_server diff --git a/examples/cpp/gcp_observability/helloworld/BUILD b/examples/cpp/gcp_observability/helloworld/BUILD new file mode 100644 index 0000000000..7894953449 --- /dev/null +++ b/examples/cpp/gcp_observability/helloworld/BUILD @@ -0,0 +1,43 @@ +# Copyright 2023 the gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +licenses(["notice"]) + +cc_binary( + name = "greeter_client", + srcs = ["greeter_client.cc"], + defines = ["BAZEL_BUILD"], + deps = [ + "//:grpc++", + "//:grpcpp_gcp_observability", + "//examples/protos:helloworld_cc_grpc", + "@com_google_absl//absl/flags:flag", + "@com_google_absl//absl/flags:parse", + ], +) + +cc_binary( + name = "greeter_server", + srcs = ["greeter_server.cc"], + defines = ["BAZEL_BUILD"], + deps = [ + "//:grpc++", + "//:grpc++_reflection", + "//:grpcpp_gcp_observability", + "//examples/protos:helloworld_cc_grpc", + "@com_google_absl//absl/flags:flag", + "@com_google_absl//absl/flags:parse", + "@com_google_absl//absl/strings:str_format", + ], +) diff --git a/examples/cpp/gcp_observability/helloworld/README.md b/examples/cpp/gcp_observability/helloworld/README.md new file mode 100644 index 0000000000..30fd39e5d6 --- /dev/null +++ b/examples/cpp/gcp_observability/helloworld/README.md @@ -0,0 +1,32 @@ +# gRPC C++ GCP Observability Hello World Example + +This example consists of a hello world client and a hello world server +instrumented with GCP Observability for logs, metrics and tracing. Note that +familiarity with the [basic hello world][] example is assumed. + +Please refer to GCP's Microservices Observability user guide for setup +instructions. + +[basic hello world]: https://grpc.io/docs/languages/cpp/quickstart + +### Run the example with configuration + +To use Observability, you should first setup and configure authorization as +mentioned in the Microservices Observability user guide. + +You need to set the `GRPC_GCP_OBSERVABILITY_CONFIG_FILE` environment variable to +point to the gRPC GCP Observability configuration file (preferred) or +alternatively set `GRPC_GCP_OBSERVABILITY_CONFIG` environment variable to gRPC +GCP Observability configuration value. This is needed by both client and server. + +Sample configurations are provided with the example. + +1. To start the observability-enabled example server on its default port of + 50051, run: `$ export + GRPC_GCP_OBSERVABILITY_CONFIG_FILE="$(pwd)/examples/cpp/gcp_observability/helloworld/server_config.json" + $ bazel run examples/cpp/gcp_observability/helloworld:greeter_server` + +2. In a different terminal window, run the observability-enabled example + client: `$ export + GRPC_GCP_OBSERVABILITY_CONFIG_FILE="$(pwd)/examples/cpp/gcp_observability/helloworld/client_config.json" + $ bazel run examples/cpp/gcp_observability/helloworld:greeter_client` diff --git a/examples/cpp/gcp_observability/helloworld/client_config.json b/examples/cpp/gcp_observability/helloworld/client_config.json new file mode 100644 index 0000000000..b9e503ba36 --- /dev/null +++ b/examples/cpp/gcp_observability/helloworld/client_config.json @@ -0,0 +1,18 @@ +{ + "cloud_monitoring": {}, + "cloud_trace": { + "sampling_rate": 1.0 + }, + "cloud_logging": { + "client_rpc_events": [{ + "methods": ["*"] + }], + "server_rpc_events": [{ + "methods": ["*"] + }] + }, + "labels": { + "environment" : "example-client" + } +} + diff --git a/examples/cpp/gcp_observability/helloworld/greeter_client.cc b/examples/cpp/gcp_observability/helloworld/greeter_client.cc new file mode 100644 index 0000000000..cee4bfb367 --- /dev/null +++ b/examples/cpp/gcp_observability/helloworld/greeter_client.cc @@ -0,0 +1,116 @@ +// +// +// Copyright 2023 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// + +#include <chrono> +#include <iostream> +#include <memory> +#include <string> +#include <thread> + +#include "absl/flags/flag.h" +#include "absl/flags/parse.h" + +#include <grpcpp/ext/gcp_observability.h> +#include <grpcpp/grpcpp.h> + +#ifdef BAZEL_BUILD +#include "examples/protos/helloworld.grpc.pb.h" +#else +#include "helloworld.grpc.pb.h" +#endif + +ABSL_FLAG(std::string, target, "localhost:50051", "Server address"); + +using grpc::Channel; +using grpc::ClientContext; +using grpc::Status; +using helloworld::Greeter; +using helloworld::HelloReply; +using helloworld::HelloRequest; + +class GreeterClient { + public: + GreeterClient(std::shared_ptr<Channel> channel) + : stub_(Greeter::NewStub(channel)) {} + + // Assembles the client's payload, sends it and presents the response back + // from the server. + std::string SayHello(const std::string& user) { + // Data we are sending to the server. + HelloRequest request; + request.set_name(user); + + // Container for the data we expect from the server. + HelloReply reply; + + // Context for the client. It could be used to convey extra information to + // the server and/or tweak certain RPC behaviors. + ClientContext context; + + // The actual RPC. + Status status = stub_->SayHello(&context, request, &reply); + + // Act upon its status. + if (status.ok()) { + return reply.message(); + } else { + std::cout << status.error_code() << ": " << status.error_message() + << std::endl; + return "RPC failed"; + } + } + + private: + std::unique_ptr<Greeter::Stub> stub_; +}; + +int main(int argc, char** argv) { + absl::ParseCommandLine(argc, argv); + // Instantiate the client. It requires a channel, out of which the actual RPCs + // are created. This channel models a connection to an endpoint specified by + // the argument "--target=" which is the only expected argument. + std::string target_str = absl::GetFlag(FLAGS_target); + // Turn on GCP Observability for the whole binary. Based on the configuration, + // this will emit observability data (stats, tracing and logging) to GCP + // backends. Note that this should be done before any other gRPC operation. + auto status = grpc::experimental::GcpObservabilityInit(); + if (!status.ok()) { + std::cerr << "GcpObservabilityInit() failed: " << status.ToString() + << std::endl; + return static_cast<int>(status.code()); + } + std::cout << "Initialized GCP Observability" << std::endl; + // We indicate that the channel isn't authenticated (use of + // InsecureChannelCredentials()). + GreeterClient greeter( + grpc::CreateChannel(target_str, grpc::InsecureChannelCredentials())); + std::string user("world"); + std::string reply = greeter.SayHello(user); + std::cout << "Greeter received: " << reply << std::endl; + // Flush out any pending Observability data + std::cout << "Closing GCP Observability" << std::endl; + grpc::experimental::GcpObservabilityClose(); + std::cout << "Sleeping for 25 seconds to make sure Observability stats and " + "tracing are flushed. Don't shut off server either." + << std::endl; + // Currently, GcpObservabilityClose() only supports flushing logs. Stats and + // tracing get automatically flushed at a regular interval, so sleep for an + // interval to make sure that those are flushed too. + std::this_thread::sleep_for(std::chrono::seconds(25)); + return 0; +} diff --git a/examples/cpp/gcp_observability/helloworld/greeter_server.cc b/examples/cpp/gcp_observability/helloworld/greeter_server.cc new file mode 100644 index 0000000000..4bc624ac45 --- /dev/null +++ b/examples/cpp/gcp_observability/helloworld/greeter_server.cc @@ -0,0 +1,122 @@ +// +// +// Copyright 2023 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// + +#include <chrono> +#include <csignal> +#include <iostream> +#include <memory> +#include <string> +#include <thread> + +#include "absl/flags/flag.h" +#include "absl/flags/parse.h" +#include "absl/strings/str_format.h" + +#include <grpcpp/ext/gcp_observability.h> +#include <grpcpp/ext/proto_server_reflection_plugin.h> +#include <grpcpp/grpcpp.h> +#include <grpcpp/health_check_service_interface.h> + +#ifdef BAZEL_BUILD +#include "examples/protos/helloworld.grpc.pb.h" +#else +#include "helloworld.grpc.pb.h" +#endif + +using grpc::Server; +using grpc::ServerBuilder; +using grpc::ServerContext; +using grpc::Status; +using helloworld::Greeter; +using helloworld::HelloReply; +using helloworld::HelloRequest; + +ABSL_FLAG(uint16_t, port, 50051, "Server port for the service"); + +namespace { + +volatile std::sig_atomic_t g_shutdown_flag = 0; + +void signal_handler(int signal) { + g_shutdown_flag = 1; + std::signal(signal, SIG_DFL); +} + +// Logic and data behind the server's behavior.W +class GreeterServiceImpl final : public Greeter::Service { + Status SayHello(ServerContext* context, const HelloRequest* request, + HelloReply* reply) override { + std::string prefix("Hello "); + reply->set_message(prefix + request->name()); + return Status::OK; + } +}; + +void RunServer(uint16_t port) { + std::string server_address = absl::StrFormat("0.0.0.0:%d", port); + GreeterServiceImpl service; + grpc::EnableDefaultHealthCheckService(true); + grpc::reflection::InitProtoReflectionServerBuilderPlugin(); + ServerBuilder builder; + // Listen on the given address without any authentication mechanism. + builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); + // Register "service" as the instance through which we'll communicate with + // clients. In this case it corresponds to an *synchronous* service. + builder.RegisterService(&service); + // Finally assemble the server. + std::unique_ptr<Server> server(builder.BuildAndStart()); + std::cout << "Server listening on " << server_address << std::endl; + // Instead of server->Wait(), we are waiting on a shutdown notification from + // SIGINT. + while (!g_shutdown_flag) { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + server->Shutdown(); +} + +} // namespace + +int main(int argc, char** argv) { + absl::ParseCommandLine(argc, argv); + // Install a signal handler for an indication to shut down server and flush + // out observability data; + std::signal(SIGINT, signal_handler); + // Turn on GCP Observability for the whole binary. Based on the configuration, + // this will emit observability data (stats, tracing and logging) to GCP + // backends. Note that this should be done before any other gRPC operation. + auto status = grpc::experimental::GcpObservabilityInit(); + if (!status.ok()) { + std::cerr << "GcpObservabilityInit() failed: " << status.ToString() + << std::endl; + return static_cast<int>(status.code()); + } + std::cout << "Initialized GCP Observability" << std::endl; + RunServer(absl::GetFlag(FLAGS_port)); + // Flush out any pending Observability data + std::cout << "Closing GCP Observability" << std::endl; + grpc::experimental::GcpObservabilityClose(); + std::cout << "Sleeping for 25 seconds to make sure Observability stats and " + "tracing are flushed.(Another Ctrl+C will immediately exit the " + "program.)" + << std::endl; + // Currently, GcpObservabilityClose() only supports flushing logs. Stats and + // tracing get automatically flushed at a regular interval, so sleep for an + // interval to make sure that those are flushed too. + std::this_thread::sleep_for(std::chrono::seconds(25)); + return 0; +} diff --git a/examples/cpp/gcp_observability/helloworld/server_config.json b/examples/cpp/gcp_observability/helloworld/server_config.json new file mode 100644 index 0000000000..d47ee4ce66 --- /dev/null +++ b/examples/cpp/gcp_observability/helloworld/server_config.json @@ -0,0 +1,18 @@ +{ + "cloud_monitoring": {}, + "cloud_trace": { + "sampling_rate": 1.0 + }, + "cloud_logging": { + "client_rpc_events": [{ + "methods": ["*"] + }], + "server_rpc_events": [{ + "methods": ["*"] + }] + }, + "labels": { + "environment" : "example-server" + } +} + |