-
Notifications
You must be signed in to change notification settings - Fork 559
Simple instrumented gRPC example #729
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
24 commits
Select commit
Hold shift + click to select a range
2fce994
Add simple gRPC example
Hablapatabla 6ebb25a
Restore errors introduced by format.sh. Explicitly include header fil…
Hablapatabla 30d64d9
Merge branch 'main' into grpc-example
lalitb c3d5bfa
Implement Lalit's proposed changes in PR #729.
Hablapatabla baeb439
Merge branch 'open-telemetry:main' into grpc-example
Hablapatabla bb178cd
Implement client-server propagation, except it doesn't work. Commit t…
Hablapatabla bbfc584
Merge branch 'main' of https://github.com/open-telemetry/opentelemetr…
Hablapatabla 139273b
Saving files before refreshing line endings
Hablapatabla 9496c3f
Normalize all the line endings
Hablapatabla 1799f32
Format and comment out debugging output from trying to implement span…
Hablapatabla f3aabc0
Merge branch 'open-telemetry:main' into grpc-example
Hablapatabla 00a707b
Merge branch 'grpc-example' of https://github.com/Hablapatabla/opente…
Hablapatabla 25ff009
Fix code snippet markdown in README and try adding block around find_…
Hablapatabla d8569a2
Revert CMakeLists so it works again after bad commit (oof).
Hablapatabla 2de0ea2
fix context propagation
lalitb 464d52b
run only with WITH_OTLP
lalitb 44dd750
revert
lalitb bc4311f
another revert try
lalitb 2fb974a
fix readme
lalitb fadde9e
fix readme
lalitb 0e3c346
format, and comments
lalitb bfaf2ce
Merge branch 'main' into grpc-example
lalitb 8eb1dc8
Merge branch 'grpc-example' of github.com:Hablapatabla/opentelemetry-…
lalitb 9404cf9
Merge branch 'main' into grpc-example
lalitb File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| if(WITH_OTLP) | ||
| add_subdirectory(otlp) | ||
| add_subdirectory(grpc) | ||
| endif() | ||
| if(WITH_JAEGER) | ||
| add_subdirectory(jaeger) | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| # Proto file | ||
| get_filename_component(proto_file "./protos/messages.proto" ABSOLUTE) | ||
| get_filename_component(proto_file_path "${proto_file}" PATH) | ||
|
|
||
| message("PATH:${proto_file_path}:${proto_file}") | ||
| # Generated sources | ||
| set(example_proto_srcs "${CMAKE_CURRENT_BINARY_DIR}/messages.pb.cc") | ||
| set(example_proto_hdrs "${CMAKE_CURRENT_BINARY_DIR}/messages.pb.h") | ||
| set(example_grpc_srcs "${CMAKE_CURRENT_BINARY_DIR}/messages.grpc.pb.cc") | ||
| set(example_grpc_hdrs "${CMAKE_CURRENT_BINARY_DIR}/messages.grpc.pb.h") | ||
|
|
||
| add_custom_command( | ||
| OUTPUT "${example_proto_srcs}" "${example_proto_hdrs}" "${example_grpc_srcs}" | ||
| "${example_grpc_hdrs}" | ||
| COMMAND | ||
| ${PROTOBUF_PROTOC_EXECUTABLE} ARGS "--grpc_out=${CMAKE_CURRENT_BINARY_DIR}" | ||
| "--cpp_out=${CMAKE_CURRENT_BINARY_DIR}" "--proto_path=${proto_file_path}" | ||
| --plugin=protoc-gen-grpc="${gRPC_CPP_PLUGIN_EXECUTABLE}" "${proto_file}") | ||
| # DEPENDS "${proto_file}") | ||
|
|
||
| # hw_grpc_proto | ||
| add_library(example_grpc_proto ${example_grpc_srcs} ${example_grpc_hdrs} | ||
| ${example_proto_srcs} ${example_proto_hdrs}) | ||
|
|
||
| include_directories( | ||
| ${CMAKE_SOURCE_DIR}/exporters/ostream/include ${CMAKE_SOURCE_DIR}/ext/include | ||
| ${CMAKE_SOURCE_DIR}/api/include/ ${CMAKE_SOURCE_DIR/}) | ||
|
|
||
| include_directories(${CMAKE_CURRENT_BINARY_DIR}) | ||
|
|
||
| if(TARGET protobuf::libprotobuf) | ||
| target_link_libraries(example_grpc_proto gRPC::grpc++ protobuf::libprotobuf) | ||
| else() | ||
| target_include_directories(example_grpc_proto ${Protobuf_INCLUDE_DIRS}) | ||
| target_link_libraries(example_grpc_proto ${Protobuf_LIBRARIES}) | ||
| endif() | ||
|
|
||
| foreach(_target client server) | ||
| add_executable(${_target} "${_target}.cpp") | ||
| target_link_libraries( | ||
| ${_target} | ||
| example_grpc_proto | ||
| protobuf::libprotobuf | ||
| gRPC::grpc++ | ||
| gRPC::grpc++_reflection | ||
| opentelemetry_trace | ||
| opentelemetry_exporter_ostream_span) | ||
| endforeach() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| # OpenTelemetry C++ Example | ||
|
|
||
| ## gRPC | ||
|
|
||
| This is a simple example that demonstrates tracing a gRPC request from client to server. There is an experimental directory in this example - the code within has been commented out to prevent any conflicts. The example shows several aspects of tracing such as: | ||
|
|
||
| * Using the `TracerProvider` | ||
| * Implementing the TextMapCarrier | ||
| * Context injection/extraction | ||
| * Span Attributes | ||
| * Span Semantic Conventions | ||
| * Using the ostream exporter | ||
| * Nested spans | ||
| * W3c Trace Context Propagation (Very soon!) | ||
|
|
||
| ### Running the example | ||
|
|
||
| 1. The example uses gRPC C++ as well as Google's protocol buffers. Make sure you have installed both | ||
| of these packages on your system, in such a way that CMake would know how to find them with this command: | ||
|
|
||
| ``find_package(gRPC)`` | ||
|
|
||
| 2. Build and Deploy the opentelementry-cpp as described in [INSTALL.md](../../INSTALL.md). Building the project will build all of the examples | ||
| and create new folders containing their executables within the 'build' directory NOT the 'examples' directory. | ||
|
|
||
| 3. Start the server from your `build/examples/grpc` directory. Both the server and client are configured to use 8800 as the default port, | ||
| but if you would like to use another port, you can specify that as an argument. | ||
|
|
||
| ```console | ||
| $ ./server [port_num] | ||
| Server listening on port: 0.0.0.0:8800 | ||
| ``` | ||
|
|
||
| 4. In a separate terminal window, run the client to make a single request: | ||
|
|
||
| ```console | ||
| $ ./client [port_num] | ||
| ... | ||
| ``` | ||
|
|
||
| 5. You should see console exporter output for both the client and server sessions. | ||
| * Client console | ||
|
|
||
| ```console | ||
| { | ||
| name : GreeterClient/Greet | ||
| trace_id : f5d16f8399be0d2c6b39d992634ffdbb | ||
| span_id : 9c79a2dd744d7d2d | ||
| tracestate : | ||
| parent_span_id: 0000000000000000 | ||
| start : 1622603339918985700 | ||
| duration : 4960500 | ||
| description : | ||
| span kind : Client | ||
| status : Ok | ||
| attributes : | ||
| rpc.grpc.status_code: 0 | ||
| net.peer.port: 8080 | ||
| net.peer.ip: 0.0.0.0 | ||
| rpc.method: Greet | ||
| rpc.service: grpc-example.GreetService | ||
| rpc.system: grpc | ||
| events : | ||
| } | ||
| ``` | ||
|
|
||
| * Server console | ||
|
|
||
| ```console | ||
| { | ||
| name : GreeterService/Greet | ||
| trace_id : f5d16f8399be0d2c6b39d992634ffdbb | ||
| span_id : 1e8a7d2d46e08573 | ||
| tracestate : | ||
| parent_span_id: 9c79a2dd744d7d2d | ||
| start : 1622603339923163800 | ||
| duration : 76400 | ||
| description : | ||
| span kind : Server | ||
| status : Ok | ||
| attributes : | ||
| rpc.grpc.status_code: 0 | ||
| rpc.method: Greet | ||
| rpc.service: GreeterService | ||
| rpc.system: grpc | ||
| events : | ||
| { | ||
| name : Processing client attributes | ||
| timestamp : 1622603339923180800 | ||
| attributes : | ||
| } | ||
| { | ||
| name : Response sent to client | ||
| timestamp : 1622603339923233700 | ||
| attributes : | ||
| } | ||
| links : | ||
| } | ||
| ``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,109 @@ | ||
| #include "tracer_common.h" | ||
| #include <iostream> | ||
| #include <memory> | ||
| #include <string> | ||
|
|
||
| #include <grpcpp/grpcpp.h> | ||
|
|
||
| #include "messages.grpc.pb.h" | ||
|
|
||
| using grpc::Channel; | ||
| using grpc::ClientContext; | ||
| using grpc::ClientReader; | ||
| using grpc::Status; | ||
|
|
||
| using grpc_example::Greeter; | ||
| using grpc_example::GreetRequest; | ||
| using grpc_example::GreetResponse; | ||
|
|
||
|
|
||
| namespace | ||
| { | ||
|
|
||
| class GreeterClient | ||
| { | ||
| public: | ||
| GreeterClient(std::shared_ptr<Channel> channel) : stub_(Greeter::NewStub(channel)) {} | ||
|
|
||
| std::string Greet(std::string ip, uint16_t port) | ||
| { | ||
| // Build gRPC Context objects and protobuf message containers | ||
| GreetRequest request; | ||
| GreetResponse response; | ||
| ClientContext context; | ||
| request.set_request("Nice to meet you!"); | ||
|
|
||
| opentelemetry::trace::StartSpanOptions options; | ||
| options.kind = opentelemetry::trace::SpanKind::kClient; | ||
|
|
||
| std::string span_name = "GreeterClient/Greet"; | ||
| auto span = get_tracer("grpc")->StartSpan(span_name, | ||
| {{"rpc.system", "grpc"}, | ||
| {"rpc.service", "grpc-example.GreetService"}, | ||
| {"rpc.method", "Greet"}, | ||
| {"net.peer.ip", ip}, | ||
| {"net.peer.port", port}}, | ||
| options); | ||
|
|
||
| auto scope = get_tracer("grpc-client")->WithActiveSpan(span); | ||
|
|
||
| // inject current context to grpc metadata | ||
| auto current_ctx = opentelemetry::context::RuntimeContext::GetCurrent(); | ||
| GrpcClientCarrier carrier(&context); | ||
| auto prop = opentelemetry::context::propagation::GlobalTextMapPropagator::GetGlobalPropagator(); | ||
| prop->Inject(carrier, current_ctx); | ||
|
|
||
| // Send request to server | ||
| Status status = stub_->Greet(&context, request, &response); | ||
| if (status.ok()) | ||
| { | ||
| span->SetStatus(opentelemetry::trace::StatusCode::kOk); | ||
| span->SetAttribute("rpc.grpc.status_code", status.error_code()); | ||
| // Make sure to end your spans! | ||
| span->End(); | ||
| return response.response(); | ||
| } | ||
| else | ||
| { | ||
| std::cout << status.error_code() << ": " << status.error_message() << std::endl; | ||
| span->SetStatus(opentelemetry::trace::StatusCode::kError); | ||
| span->SetAttribute("rpc.grpc.status_code", status.error_code()); | ||
| // Make sure to end your spans! | ||
| span->End(); | ||
| return "RPC failed"; | ||
| } | ||
| } | ||
|
|
||
| private: | ||
| std::unique_ptr<Greeter::Stub> stub_; | ||
| }; // GreeterClient class | ||
|
|
||
| void RunClient(uint16_t port) | ||
| { | ||
| GreeterClient greeter( | ||
| grpc::CreateChannel("0.0.0.0:" + std::to_string(port), grpc::InsecureChannelCredentials())); | ||
| std::string response = greeter.Greet("0.0.0.0", port); | ||
| std::cout << "grpc_server says: " << response << std::endl; | ||
| } | ||
| } // namespace | ||
|
|
||
| int main(int argc, char **argv) | ||
| { | ||
| initTracer(); | ||
| // set global propagator | ||
| opentelemetry::context::propagation::GlobalTextMapPropagator::SetGlobalPropagator( | ||
| nostd::shared_ptr<opentelemetry::context::propagation::TextMapPropagator>( | ||
| new opentelemetry::trace::propagation::HttpTraceContext())); | ||
| constexpr uint16_t default_port = 8800; | ||
| uint16_t port; | ||
| if (argc > 1) | ||
| { | ||
| port = atoi(argv[1]); | ||
| } | ||
| else | ||
| { | ||
| port = default_port; | ||
| } | ||
| RunClient(port); | ||
| return 0; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| syntax = "proto3"; | ||
|
|
||
| package grpc_example; | ||
|
|
||
| service Greeter { | ||
| rpc Greet(GreetRequest) returns (GreetResponse) {} | ||
| } | ||
|
|
||
| message GreetRequest { | ||
| string request = 1; | ||
| } | ||
|
|
||
| message GreetResponse { | ||
| string response = 1; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,114 @@ | ||
| #include "messages.grpc.pb.h" | ||
| #include "tracer_common.h" | ||
| #include "opentelemetry/trace/span_context_kv_iterable_view.h" | ||
|
|
||
| #include <grpcpp/grpcpp.h> | ||
| #include <grpcpp/server.h> | ||
| #include <grpcpp/server_builder.h> | ||
| #include <grpcpp/server_context.h> | ||
|
|
||
| #include <chrono> | ||
| #include <fstream> | ||
| #include <sstream> | ||
| #include <string> | ||
| #include <thread> | ||
| #include <map> | ||
|
|
||
| using grpc::Server; | ||
| using grpc::ServerBuilder; | ||
| using grpc::ServerContext; | ||
| using grpc::ServerWriter; | ||
| using grpc::Status; | ||
|
|
||
| using grpc_example::Greeter; | ||
| using grpc_example::GreetRequest; | ||
| using grpc_example::GreetResponse; | ||
|
|
||
| using Span = opentelemetry::trace::Span; | ||
| using SpanContext = opentelemetry::trace::SpanContext; | ||
|
|
||
| namespace | ||
| { | ||
| class GreeterServer final : public Greeter::Service | ||
| { | ||
| public: | ||
| Status Greet(ServerContext *context, | ||
| const GreetRequest *request, | ||
| GreetResponse *response) override | ||
| { | ||
| for( auto elem: context->client_metadata()) { | ||
| std::cout << "ELEM: " << elem.first << " " << elem.second << "\n"; | ||
| } | ||
|
|
||
| // Create a SpanOptions object and set the kind to Server to inform OpenTel. | ||
| opentelemetry::trace::StartSpanOptions options; | ||
| options.kind = opentelemetry::trace::SpanKind::kServer; | ||
|
|
||
| // extract context from grpc metadata | ||
| GrpcServerCarrier carrier(context); | ||
|
|
||
| auto prop = opentelemetry::context::propagation::GlobalTextMapPropagator::GetGlobalPropagator(); | ||
| auto current_ctx = opentelemetry::context::RuntimeContext::GetCurrent(); | ||
| auto new_context = prop->Extract(carrier, current_ctx); | ||
| options.parent = opentelemetry::trace::propagation::GetSpan(new_context)->GetContext(); | ||
|
|
||
| std::string span_name = "GreeterService/Greet"; | ||
| auto span = get_tracer("grpc") | ||
| ->StartSpan(span_name, | ||
| {{"rpc.system", "grpc"}, | ||
| {"rpc.service", "GreeterService"}, | ||
| {"rpc.method", "Greet"}, | ||
| {"rpc.grpc.status_code", 0}}, | ||
| options); | ||
| auto scope = get_tracer("grpc")->WithActiveSpan(span); | ||
|
|
||
| // Fetch and parse whatever HTTP headers we can from the gRPC request. | ||
| span->AddEvent("Processing client attributes"); | ||
|
|
||
| std::string req = request->request(); | ||
| std::cout << std::endl << "grpc_client says: " << req << std::endl; | ||
| std::string message = "The pleasure is mine."; | ||
| // Send response to client | ||
| response->set_response(message); | ||
| span->AddEvent("Response sent to client"); | ||
|
|
||
| span->SetStatus(opentelemetry::trace::StatusCode::kOk); | ||
| // Make sure to end your spans! | ||
| span->End(); | ||
| return Status::OK; | ||
| } | ||
| }; // GreeterServer class | ||
|
|
||
| void RunServer(uint16_t port) | ||
| { | ||
| std::string address("0.0.0.0:" + std::to_string(port)); | ||
| GreeterServer service; | ||
| ServerBuilder builder; | ||
|
|
||
| builder.RegisterService(&service); | ||
| builder.AddListeningPort(address, grpc::InsecureServerCredentials()); | ||
|
|
||
| std::unique_ptr<Server> server(builder.BuildAndStart()); | ||
| std::cout << "Server listening on port: " << address << std::endl; | ||
| server->Wait(); | ||
| server->Shutdown(); | ||
| } | ||
| } // namespace | ||
|
|
||
| int main(int argc, char **argv) | ||
| { | ||
| initTracer(); | ||
| constexpr uint16_t default_port = 8800; | ||
| uint16_t port; | ||
| if (argc > 1) | ||
| { | ||
| port = atoi(argv[1]); | ||
| } | ||
| else | ||
| { | ||
| port = default_port; | ||
| } | ||
|
|
||
| RunServer(port); | ||
| return 0; | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.