Skip to content
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

Simple instrumented gRPC example #729

Merged
merged 24 commits into from
Jun 3, 2021
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
2fce994
Add simple gRPC example
Hablapatabla May 8, 2021
6ebb25a
Restore errors introduced by format.sh. Explicitly include header fil…
Hablapatabla May 8, 2021
30d64d9
Merge branch 'main' into grpc-example
lalitb May 8, 2021
c3d5bfa
Implement Lalit's proposed changes in PR #729.
Hablapatabla May 8, 2021
baeb439
Merge branch 'open-telemetry:main' into grpc-example
Hablapatabla May 8, 2021
bb178cd
Implement client-server propagation, except it doesn't work. Commit t…
Hablapatabla May 10, 2021
bbfc584
Merge branch 'main' of https://github.com/open-telemetry/opentelemetr…
Hablapatabla May 10, 2021
139273b
Saving files before refreshing line endings
Hablapatabla May 10, 2021
9496c3f
Normalize all the line endings
Hablapatabla May 10, 2021
1799f32
Format and comment out debugging output from trying to implement span…
Hablapatabla May 11, 2021
f3aabc0
Merge branch 'open-telemetry:main' into grpc-example
Hablapatabla May 11, 2021
00a707b
Merge branch 'grpc-example' of https://github.com/Hablapatabla/opente…
Hablapatabla May 11, 2021
25ff009
Fix code snippet markdown in README and try adding block around find_…
Hablapatabla May 11, 2021
d8569a2
Revert CMakeLists so it works again after bad commit (oof).
Hablapatabla May 11, 2021
2de0ea2
fix context propagation
lalitb Jun 2, 2021
464d52b
run only with WITH_OTLP
lalitb Jun 2, 2021
44dd750
revert
lalitb Jun 2, 2021
bc4311f
another revert try
lalitb Jun 2, 2021
2fb974a
fix readme
lalitb Jun 2, 2021
fadde9e
fix readme
lalitb Jun 2, 2021
0e3c346
format, and comments
lalitb Jun 2, 2021
bfaf2ce
Merge branch 'main' into grpc-example
lalitb Jun 2, 2021
8eb1dc8
Merge branch 'grpc-example' of github.com:Hablapatabla/opentelemetry-…
lalitb Jun 2, 2021
9404cf9
Merge branch 'main' into grpc-example
lalitb Jun 3, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ add_subdirectory(metrics_simple)
add_subdirectory(multithreaded)
add_subdirectory(multi_processor)
add_subdirectory(http)
add_subdirectory(grpc)
62 changes: 62 additions & 0 deletions examples/grpc/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
find_package(gRPC)
find_package(Protobuf)

if(NOT Protobuf_FOUND)
message(WARNING "Aborting grpc example build, protobuf not found.")
elseif(NOT gRPC_FOUND)
message(WARNING "Aborting grpc example build, grpc not found.")
else()
set(_PROTOBUF_PROTOC $<TARGET_FILE:protobuf::protoc>)
set(_GRPC_GRPCPP gRPC::grpc++)
set(_GRPC_CPP_PLUGIN_EXECUTABLE $<TARGET_FILE:gRPC::grpc_cpp_plugin>)

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}/protos)

get_filename_component(
hw_proto ${CMAKE_CURRENT_SOURCE_DIR}/protos/messages.proto ABSOLUTE)
get_filename_component(hw_proto_path "${hw_proto}" PATH)

set(hw_proto_srcs "${CMAKE_CURRENT_BINARY_DIR}/messages.pb.cc")
set(hw_proto_hdrs "${CMAKE_CURRENT_BINARY_DIR}/messages.pb.h")
set(hw_grpc_srcs "${CMAKE_CURRENT_BINARY_DIR}/messages.grpc.pb.cc")
set(hw_grpc_hdrs "${CMAKE_CURRENT_BINARY_DIR}/messages.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_directories("${CMAKE_CURRENT_BINARY_DIR}")

add_library(grpc_foo_library grpc_foo_lib/foo_split.cc)

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})

foreach(_target client server)
add_executable(${_target} "${_target}.cc")
target_link_libraries(
${_target}
hw_grpc_proto
grpc_foo_library
${_REFLECTION}
${_GRPC_GRPCPP}
${_PROTOBUF_LIBPROTOBUF}
${CMAKE_THREAD_LIBS_INIT}
${CORE_RUNTIME_LIBS}
opentelemetry_trace
opentelemetry_exporter_ostream_span)
endforeach()
endif()
122 changes: 122 additions & 0 deletions examples/grpc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# 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)```

If you install these with a package manager like '''brew''' or '''apt''', you should not need to do extra work.

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 : f898b8bca93936f112a56b710bb888eb
span_id : 8354bf34f7de06a0
tracestate :
parent_span_id: 0000000000000000
start : 1620434679192923000
duration : 1571169
description :
span kind : Client
status : Ok
attributes :
rpc.grpc.status_code: 0
net.peer.port: 8800
rpc.system: grpc
net.peer.ip: 0.0.0.0
rpc.method: Greet
rpc.service: grpc-example.GreetService
events :
links :
}
```

* Server console

```console
{
name : splitfunc
trace_id : 0836f1469dac75fddb57df13bcf33420
span_id : 97b3f69fae5c0e15
tracestate :
parent_span_id: 3d5fcaccc5617153
start : 1620435268681957000
duration : 38026
description :
span kind : Internal
status : Unset
attributes :
events :
links :
}

{
name : splitlib
trace_id : 0836f1469dac75fddb57df13bcf33420
span_id : 3d5fcaccc5617153
tracestate :
parent_span_id: a6aa48220c511354
start : 1620435268681937000
duration : 99145
description :
span kind : Internal
status : Unset
attributes :
events :
links :
}

{
name : GreeterService/Greet
trace_id : 0836f1469dac75fddb57df13bcf33420
span_id : a6aa48220c511354
tracestate :
parent_span_id: 0000000000000000
start : 1620435268681893000
duration : 178531
description :
span kind : Serve
status : Ok
attributes :
rpc.grpc.status_code: 0
rpc.method: Greet
rpc.service: GreeterService
rpc.system: grpc
events :
links :
}
```
113 changes: 113 additions & 0 deletions examples/grpc/client.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
#include "grpc_foo_lib/foo_split.h"
#include "grpc_foo_lib/grpc_map_carrier.h"
#include "messages.grpc.pb.h"
#include "tracer_common.h"

#include <grpcpp/grpcpp.h>
#include <iostream>
#include <string>

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;
// Spans are only as useful as the information that you put in them.
// Even though this is a client service, it can still be useful to add
// as much data as possible. We add attributes for peer ip and port, both
// because it is required per OpenTelemetry's rpc semantic conventions,
// and because it could still be useful to a debugger in the future.
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")->WithActiveSpan(span);

/*
Commented out some debugging output, in case a reviewer finds it useful
opentelemetry::nostd::span<const uint8_t, 8> sp = span->GetContext().span_id().Id();
for(const uint8_t &e : sp) {
std::cout << unsigned(e) << ' ';
}
std::cout << '\n';*/
auto current_ctx = opentelemetry::context::RuntimeContext::GetCurrent();
// Experimented with opentelemetry::ext::http::client::Headers here too
gRPCMapCarrier<std::map<std::string, std::string>> carrier;
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();
constexpr uint16_t default_port = 8800;
uint16_t port;
if (argc > 1)
{
port = atoi(argv[1]);
}
else
{
port = default_port;
}
RunClient(port);
return 0;
}
Loading