diff --git a/examples/cpp/otel/codelab/BUILD b/examples/cpp/otel/codelab/BUILD new file mode 100644 index 00000000000..2cc92ae3f4a --- /dev/null +++ b/examples/cpp/otel/codelab/BUILD @@ -0,0 +1,99 @@ +# 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"]) + +package( + default_visibility = ["//examples/cpp:__subpackages__"], +) + +cc_library( + name = "util", + srcs = ["util.cc"], + hdrs = ["util.h"], + defines = ["BAZEL_BUILD"], + deps = [ + "//:grpc++", + "//examples/protos:helloworld_cc_grpc", + "@io_opentelemetry_cpp//sdk/src/metrics", + ], +) + +cc_binary( + name = "greeter_callback_client", + srcs = ["greeter_callback_client.cc"], + defines = ["BAZEL_BUILD"], + deps = [ + "util", + "//:grpc++", + "//:grpcpp_otel_plugin", + "//examples/cpp/otel:util", + "@com_google_absl//absl/flags:flag", + "@com_google_absl//absl/flags:parse", + "@io_opentelemetry_cpp//exporters/prometheus:prometheus_exporter", + "@io_opentelemetry_cpp//sdk/src/metrics", + ], +) + +cc_binary( + name = "greeter_callback_server", + srcs = ["greeter_callback_server.cc"], + defines = ["BAZEL_BUILD"], + deps = [ + "util", + "//:grpc++", + "//:grpc++_reflection", + "//:grpcpp_otel_plugin", + "//examples/cpp/otel:util", + "@com_google_absl//absl/flags:flag", + "@com_google_absl//absl/flags:parse", + "@com_google_absl//absl/strings:str_format", + "@io_opentelemetry_cpp//exporters/prometheus:prometheus_exporter", + "@io_opentelemetry_cpp//sdk/src/metrics", + ], +) + +cc_binary( + name = "greeter_callback_client_solution", + srcs = ["greeter_callback_client_solution.cc"], + defines = ["BAZEL_BUILD"], + deps = [ + "util", + "//:grpc++", + "//:grpcpp_otel_plugin", + "//examples/cpp/otel:util", + "@com_google_absl//absl/flags:flag", + "@com_google_absl//absl/flags:parse", + "@io_opentelemetry_cpp//exporters/prometheus:prometheus_exporter", + "@io_opentelemetry_cpp//sdk/src/metrics", + ], +) + +cc_binary( + name = "greeter_callback_server_solution", + srcs = ["greeter_callback_server_solution.cc"], + defines = ["BAZEL_BUILD"], + deps = [ + "util", + "//:grpc++", + "//:grpc++_reflection", + "//:grpcpp_otel_plugin", + "//examples/cpp/otel:util", + "@com_google_absl//absl/flags:flag", + "@com_google_absl//absl/flags:parse", + "@com_google_absl//absl/strings:str_format", + "@io_opentelemetry_cpp//exporters/prometheus:prometheus_exporter", + "@io_opentelemetry_cpp//sdk/src/metrics", + ], +) diff --git a/examples/cpp/otel/codelab/CMakeLists.txt b/examples/cpp/otel/codelab/CMakeLists.txt new file mode 100644 index 00000000000..6ce38d77a2f --- /dev/null +++ b/examples/cpp/otel/codelab/CMakeLists.txt @@ -0,0 +1,87 @@ +# Copyright 2018 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. +# +# cmake build file for C++ gRPC OpenTelemetry example. +# Assumes absl, protobuf, prometheus-cpp, opentelemetry-cpp and gRPC (with -DgRPC_BUILD_OPENTELEMETRY_PLUGIN=ON) have been installed using cmake. +# See cmake_externalproject/CMakeLists.txt for all-in-one cmake build +# that automatically builds all the dependencies before building helloworld. + +cmake_minimum_required(VERSION 3.13) + +project(grpc_opentelemetry_example C CXX) + +include(../../cmake/common.cmake) + +# Find prometheus-cpp package +find_package(prometheus-cpp CONFIG REQUIRED) + +# Find opentelemetry-cpp package +find_package(opentelemetry-cpp CONFIG REQUIRED) + +# Proto file +get_filename_component(hw_proto "../../../protos/helloworld.proto" ABSOLUTE) +get_filename_component(hw_proto_path "${hw_proto}" PATH) + +# Generated sources +set(hw_proto_srcs "${CMAKE_CURRENT_BINARY_DIR}/helloworld.pb.cc") +set(hw_proto_hdrs "${CMAKE_CURRENT_BINARY_DIR}/helloworld.pb.h") +set(hw_grpc_srcs "${CMAKE_CURRENT_BINARY_DIR}/helloworld.grpc.pb.cc") +set(hw_grpc_hdrs "${CMAKE_CURRENT_BINARY_DIR}/helloworld.grpc.pb.h") +add_custom_command( + OUTPUT "${hw_proto_srcs}" "${hw_proto_hdrs}" "${hw_grpc_srcs}" "${hw_grpc_hdrs}" + COMMAND ${_PROTOBUF_PROTOC} + ARGS --grpc_out "${CMAKE_CURRENT_BINARY_DIR}" + --cpp_out "${CMAKE_CURRENT_BINARY_DIR}" + -I "${hw_proto_path}" + --plugin=protoc-gen-grpc="${_GRPC_CPP_PLUGIN_EXECUTABLE}" + "${hw_proto}" + DEPENDS "${hw_proto}") + +# Include generated *.pb.h files +include_directories("${CMAKE_CURRENT_BINARY_DIR}") +include_directories("${CMAKE_SOURCE_DIR}") + +# hw_grpc_proto +add_library(hw_grpc_proto + ${hw_grpc_srcs} + ${hw_grpc_hdrs} + ${hw_proto_srcs} + ${hw_proto_hdrs}) +target_link_libraries(hw_grpc_proto + ${_REFLECTION} + ${_GRPC_GRPCPP} + ${_PROTOBUF_LIBPROTOBUF}) + +# util +add_library(util + "util.cc") +target_link_libraries(util + hw_grpc_proto + opentelemetry-cpp::metrics + ${_GRPC_GRPCPP} + ${_REFLECTION} + ${_PROTOBUF_LIBPROTOBUF}) + +# Targets greeter_callback_(client|server) greeter_callback_(client|server)_solution +foreach(_target + greeter_callback_client greeter_callback_server greeter_callback_client_solution greeter_callback_server_solution) + add_executable(${_target} "${_target}.cc") + target_link_libraries(${_target} + absl::flags + absl::flags_parse + opentelemetry-cpp::metrics + opentelemetry-cpp::prometheus_exporter + gRPC::grpcpp_otel_plugin + util) +endforeach() diff --git a/examples/cpp/otel/codelab/greeter_callback_client.cc b/examples/cpp/otel/codelab/greeter_callback_client.cc new file mode 100644 index 00000000000..d9eab4e9edd --- /dev/null +++ b/examples/cpp/otel/codelab/greeter_callback_client.cc @@ -0,0 +1,138 @@ +/* + * + * Copyright 2021 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. + * + */ + +// Explicitly define HAVE_ABSEIL to avoid conflict with OTel's Abseil +// version. Refer +// https://github.com/open-telemetry/opentelemetry-cpp/issues/1042. +#ifndef HAVE_ABSEIL +#define HAVE_ABSEIL +#endif + +#include +#include +#include + +#include "absl/flags/flag.h" +#include "absl/flags/parse.h" +#include "opentelemetry/exporters/prometheus/exporter_factory.h" +#include "opentelemetry/exporters/prometheus/exporter_options.h" +#include "opentelemetry/sdk/metrics/meter_provider.h" + +#include +#include + +#ifdef BAZEL_BUILD +#include "examples/cpp/otel/codelab/util.h" +#include "examples/protos/helloworld.grpc.pb.h" +#else +#include "helloworld.grpc.pb.h" +#include "util.h" +#endif + +ABSL_FLAG(std::string, target, "localhost:50051", "Server address"); +ABSL_FLAG(std::string, prometheus_endpoint, "localhost:9465", + "Prometheus exporter endpoint"); + +namespace { + +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) + : 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. + std::mutex mu; + std::condition_variable cv; + bool done = false; + Status status; + stub_->async()->SayHello(&context, &request, &reply, + [&mu, &cv, &done, &status](Status s) { + status = std::move(s); + std::lock_guard lock(mu); + done = true; + cv.notify_one(); + }); + + std::unique_lock lock(mu); + while (!done) { + cv.wait(lock); + } + + // 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 stub_; +}; + +void RunClient(const std::string& target_str) { + // 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. + grpc::ChannelArguments args; + // Continuously send RPCs every second. + while (true) { + GreeterClient greeter(grpc::CreateCustomChannel( + target_str, grpc::InsecureChannelCredentials(), args)); + std::string user("world"); + std::string reply = greeter.SayHello(user); + std::cout << "Greeter received: " << reply << std::endl; + std::this_thread::sleep_for(std::chrono::seconds(1)); + } +} + +} // namespace + +int main(int argc, char** argv) { + absl::ParseCommandLine(argc, argv); + + // CODELAB HINT : Add code to register gRPC OpenTelemetry plugin here. + + // Continuously send RPCs. + RunClient(absl::GetFlag(FLAGS_target)); + + return 0; +} diff --git a/examples/cpp/otel/codelab/greeter_callback_client_solution.cc b/examples/cpp/otel/codelab/greeter_callback_client_solution.cc new file mode 100644 index 00000000000..a3a8ffe51f1 --- /dev/null +++ b/examples/cpp/otel/codelab/greeter_callback_client_solution.cc @@ -0,0 +1,158 @@ +/* + * + * Copyright 2021 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. + * + */ + +// Explicitly define HAVE_ABSEIL to avoid conflict with OTel's Abseil +// version. Refer +// https://github.com/open-telemetry/opentelemetry-cpp/issues/1042. +#ifndef HAVE_ABSEIL +#define HAVE_ABSEIL +#endif + +#include +#include +#include + +#include "absl/flags/flag.h" +#include "absl/flags/parse.h" +#include "opentelemetry/exporters/prometheus/exporter_factory.h" +#include "opentelemetry/exporters/prometheus/exporter_options.h" +#include "opentelemetry/sdk/metrics/meter_provider.h" + +#include +#include + +#ifdef BAZEL_BUILD +#include "examples/cpp/otel/codelab/util.h" +#include "examples/protos/helloworld.grpc.pb.h" +#else +#include "helloworld.grpc.pb.h" +#include "util.h" +#endif + +ABSL_FLAG(std::string, target, "localhost:50051", "Server address"); +ABSL_FLAG(std::string, prometheus_endpoint, "localhost:9465", + "Prometheus exporter endpoint"); + +namespace { + +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) + : 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. + std::mutex mu; + std::condition_variable cv; + bool done = false; + Status status; + stub_->async()->SayHello(&context, &request, &reply, + [&mu, &cv, &done, &status](Status s) { + status = std::move(s); + std::lock_guard lock(mu); + done = true; + cv.notify_one(); + }); + + std::unique_lock lock(mu); + while (!done) { + cv.wait(lock); + } + + // 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 stub_; +}; + +void RunClient(const std::string& target_str) { + // 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. + grpc::ChannelArguments args; + // Continuously send RPCs every second. + while (true) { + GreeterClient greeter(grpc::CreateCustomChannel( + target_str, grpc::InsecureChannelCredentials(), args)); + std::string user("world"); + std::string reply = greeter.SayHello(user); + std::cout << "Greeter received: " << reply << std::endl; + std::this_thread::sleep_for(std::chrono::seconds(1)); + } +} + +} // namespace + +int main(int argc, char** argv) { + absl::ParseCommandLine(argc, argv); + // CODELAB HINT : Add code to register OpenTelemetry plugin here. + // Register a global gRPC OpenTelemetry plugin configured with a prometheus + // exporter. + opentelemetry::exporter::metrics::PrometheusExporterOptions opts; + opts.url = absl::GetFlag(FLAGS_prometheus_endpoint); + auto prometheus_exporter = + opentelemetry::exporter::metrics::PrometheusExporterFactory::Create(opts); + auto meter_provider = + std::make_shared(); + // The default histogram boundaries are not granular enough for RPCs. Override + // the "grpc.client.attempt.duration" view as recommended by + // https://github.com/grpc/proposal/blob/master/A66-otel-stats.md. + AddLatencyView(meter_provider.get(), "grpc.client.attempt.duration", "s"); + meter_provider->AddMetricReader(std::move(prometheus_exporter)); + auto status = grpc::OpenTelemetryPluginBuilder() + .SetMeterProvider(std::move(meter_provider)) + .BuildAndRegisterGlobal(); + if (!status.ok()) { + std::cerr << "Failed to register gRPC OpenTelemetry Plugin: " + << status.ToString() << std::endl; + return static_cast(status.code()); + } + + // Continuously send RPCs. + RunClient(absl::GetFlag(FLAGS_target)); + + return 0; +} diff --git a/examples/cpp/otel/codelab/greeter_callback_server.cc b/examples/cpp/otel/codelab/greeter_callback_server.cc new file mode 100644 index 00000000000..bba7c9ce072 --- /dev/null +++ b/examples/cpp/otel/codelab/greeter_callback_server.cc @@ -0,0 +1,112 @@ +/* + * + * Copyright 2021 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. + * + */ + +// Explicitly define HAVE_ABSEIL to avoid conflict with OTel's Abseil +// version. Refer +// https://github.com/open-telemetry/opentelemetry-cpp/issues/1042. +#ifndef HAVE_ABSEIL +#define HAVE_ABSEIL +#endif + +#include +#include +#include + +#include "absl/flags/flag.h" +#include "absl/flags/parse.h" +#include "absl/strings/str_format.h" +#include "opentelemetry/exporters/prometheus/exporter_factory.h" +#include "opentelemetry/exporters/prometheus/exporter_options.h" +#include "opentelemetry/sdk/metrics/meter_provider.h" + +#include +#include +#include +#include + +#ifdef BAZEL_BUILD +#include "examples/cpp/otel/codelab/util.h" +#include "examples/protos/helloworld.grpc.pb.h" +#else +#include "helloworld.grpc.pb.h" +#include "util.h" +#endif + +ABSL_FLAG(uint16_t, port, 50051, "Server port for the service"); +ABSL_FLAG(std::string, prometheus_endpoint, "localhost:9464", + "Prometheus exporter endpoint"); + +namespace { + +using grpc::CallbackServerContext; +using grpc::Server; +using grpc::ServerBuilder; +using grpc::ServerUnaryReactor; +using grpc::Status; +using helloworld::Greeter; +using helloworld::HelloReply; +using helloworld::HelloRequest; + +// Logic and data behind the server's behavior. +class GreeterServiceImpl final : public Greeter::CallbackService { + ServerUnaryReactor* SayHello(CallbackServerContext* context, + const HelloRequest* request, + HelloReply* reply) override { + std::string prefix("Hello "); + reply->set_message(prefix + request->name()); + + // CODELAB HINT: This sleep seems suspicious. + std::this_thread::sleep_for(std::chrono::seconds(5)); + + ServerUnaryReactor* reactor = context->DefaultReactor(); + reactor->Finish(Status::OK); + return reactor; + } +}; + +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(builder.BuildAndStart()); + std::cout << "Server listening on " << server_address << std::endl; + + // Wait for the server to shutdown. Note that some other thread must be + // responsible for shutting down the server for this call to ever return. + server->Wait(); +} + +} // namespace + +int main(int argc, char** argv) { + absl::ParseCommandLine(argc, argv); + + // CODELAB HINT : Add code to register gRPC OpenTelemetry plugin here. + + RunServer(absl::GetFlag(FLAGS_port)); + return 0; +} diff --git a/examples/cpp/otel/codelab/greeter_callback_server_solution.cc b/examples/cpp/otel/codelab/greeter_callback_server_solution.cc new file mode 100644 index 00000000000..a53ab288af4 --- /dev/null +++ b/examples/cpp/otel/codelab/greeter_callback_server_solution.cc @@ -0,0 +1,127 @@ +/* + * + * Copyright 2021 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. + * + */ + +// Explicitly define HAVE_ABSEIL to avoid conflict with OTel's Abseil +// version. Refer +// https://github.com/open-telemetry/opentelemetry-cpp/issues/1042. +#ifndef HAVE_ABSEIL +#define HAVE_ABSEIL +#endif + +#include +#include +#include + +#include "absl/flags/flag.h" +#include "absl/flags/parse.h" +#include "absl/strings/str_format.h" +#include "opentelemetry/exporters/prometheus/exporter_factory.h" +#include "opentelemetry/exporters/prometheus/exporter_options.h" +#include "opentelemetry/sdk/metrics/meter_provider.h" + +#include +#include +#include +#include + +#ifdef BAZEL_BUILD +#include "examples/cpp/otel/codelab/util.h" +#include "examples/protos/helloworld.grpc.pb.h" +#else +#include "helloworld.grpc.pb.h" +#include "util.h" +#endif + +ABSL_FLAG(uint16_t, port, 50051, "Server port for the service"); +ABSL_FLAG(std::string, prometheus_endpoint, "localhost:9464", + "Prometheus exporter endpoint"); + +namespace { + +using grpc::CallbackServerContext; +using grpc::Server; +using grpc::ServerBuilder; +using grpc::ServerUnaryReactor; +using grpc::Status; +using helloworld::Greeter; +using helloworld::HelloReply; +using helloworld::HelloRequest; + +// Logic and data behind the server's behavior. +class GreeterServiceImpl final : public Greeter::CallbackService { + ServerUnaryReactor* SayHello(CallbackServerContext* context, + const HelloRequest* request, + HelloReply* reply) override { + std::string prefix("Hello "); + reply->set_message(prefix + request->name()); + + ServerUnaryReactor* reactor = context->DefaultReactor(); + reactor->Finish(Status::OK); + return reactor; + } +}; + +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(builder.BuildAndStart()); + std::cout << "Server listening on " << server_address << std::endl; + + // Wait for the server to shutdown. Note that some other thread must be + // responsible for shutting down the server for this call to ever return. + server->Wait(); +} + +} // namespace + +int main(int argc, char** argv) { + absl::ParseCommandLine(argc, argv); + // Register a global gRPC OpenTelemetry plugin configured with a prometheus + // exporter. + opentelemetry::exporter::metrics::PrometheusExporterOptions opts; + opts.url = absl::GetFlag(FLAGS_prometheus_endpoint); + auto prometheus_exporter = + opentelemetry::exporter::metrics::PrometheusExporterFactory::Create(opts); + auto meter_provider = + std::make_shared(); + // The default histogram boundaries are not granular enough for RPCs. Override + // the "grpc.server.call.duration" view as recommended by + // https://github.com/grpc/proposal/blob/master/A66-otel-stats.md. + AddLatencyView(meter_provider.get(), "grpc.server.call.duration", "s"); + meter_provider->AddMetricReader(std::move(prometheus_exporter)); + auto status = grpc::OpenTelemetryPluginBuilder() + .SetMeterProvider(std::move(meter_provider)) + .BuildAndRegisterGlobal(); + if (!status.ok()) { + std::cerr << "Failed to register gRPC OpenTelemetry Plugin: " + << status.ToString() << std::endl; + return static_cast(status.code()); + } + RunServer(absl::GetFlag(FLAGS_port)); + return 0; +} diff --git a/examples/cpp/otel/codelab/util.cc b/examples/cpp/otel/codelab/util.cc new file mode 100644 index 00000000000..a8fcce95663 --- /dev/null +++ b/examples/cpp/otel/codelab/util.cc @@ -0,0 +1,70 @@ +// +// +// Copyright 2024 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. +// +// + +// Explicitly define HAVE_ABSEIL to avoid conflict with OTel's Abseil +// version. Refer +// https://github.com/open-telemetry/opentelemetry-cpp/issues/1042. +#ifndef HAVE_ABSEIL +#define HAVE_ABSEIL +#endif + +#include "opentelemetry/sdk/metrics/view/instrument_selector_factory.h" +#include "opentelemetry/sdk/metrics/view/meter_selector_factory.h" +#include "opentelemetry/sdk/metrics/view/view_factory.h" + +#include + +#ifdef BAZEL_BUILD +#include "examples/cpp/otel/codelab/util.h" +#include "examples/protos/helloworld.grpc.pb.h" +#else +#include "helloworld.grpc.pb.h" +#include "util.h" +#endif + +using grpc::CallbackServerContext; +using grpc::Channel; +using grpc::ClientContext; +using grpc::Server; +using grpc::ServerBuilder; +using grpc::ServerUnaryReactor; +using grpc::Status; +using helloworld::Greeter; +using helloworld::HelloReply; +using helloworld::HelloRequest; + +void AddLatencyView(opentelemetry::sdk::metrics::MeterProvider* provider, + const std::string& name, const std::string& unit) { + auto histogram_config = std::make_shared< + opentelemetry::sdk::metrics::HistogramAggregationConfig>(); + histogram_config->boundaries_ = { + 0, 0.00001, 0.00005, 0.0001, 0.0003, 0.0006, 0.0008, 0.001, 0.002, + 0.003, 0.004, 0.005, 0.006, 0.008, 0.01, 0.013, 0.016, 0.02, + 0.025, 0.03, 0.04, 0.05, 0.065, 0.08, 0.1, 0.13, 0.16, + 0.2, 0.25, 0.3, 0.4, 0.5, 0.65, 0.8, 1, 2, + 5, 10, 20, 50, 100}; + provider->AddView( + opentelemetry::sdk::metrics::InstrumentSelectorFactory::Create( + opentelemetry::sdk::metrics::InstrumentType::kHistogram, name, unit), + opentelemetry::sdk::metrics::MeterSelectorFactory::Create( + "grpc-c++", grpc::Version(), ""), + opentelemetry::sdk::metrics::ViewFactory::Create( + name, "", unit, + opentelemetry::sdk::metrics::AggregationType::kHistogram, + std::move(histogram_config))); +} diff --git a/examples/cpp/otel/codelab/util.h b/examples/cpp/otel/codelab/util.h new file mode 100644 index 00000000000..cf140de16f3 --- /dev/null +++ b/examples/cpp/otel/codelab/util.h @@ -0,0 +1,31 @@ +// +// +// Copyright 2024 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. +// +// + +#ifndef GRPCPP_EXAMPLES_CPP_OTEL_CODELAB_UTIL_H +#define GRPCPP_EXAMPLES_CPP_OTEL_CODELAB_UTIL_H + +#include + +#include "opentelemetry/sdk/metrics/meter_provider.h" + +// Helper function that adds view for gRPC latency instrument \a name with unit +// \a unit with bucket boundaries that are more useful for RPCs. +void AddLatencyView(opentelemetry::sdk::metrics::MeterProvider* provider, + const std::string& name, const std::string& unit); + +#endif // GRPCPP_EXAMPLES_CPP_OTEL_UTIL_H