-
Notifications
You must be signed in to change notification settings - Fork 35
Expand file tree
/
Copy pathtrace_service_client.hpp
More file actions
147 lines (116 loc) · 4.09 KB
/
Copy pathtrace_service_client.hpp
File metadata and controls
147 lines (116 loc) · 4.09 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#pragma once
#include <functional>
#include <grpcpp/grpcpp.h>
#include <grpcpp/alarm.h>
#include <opentelemetry/proto/collector/trace/v1/trace_service.grpc.pb.h>
namespace otel_proto_trace = opentelemetry::proto::collector::trace::v1;
struct Target {
typedef std::vector<std::pair<std::string, std::string>> HeaderVec;
std::string endpoint;
bool ssl;
std::string trustedCert;
std::string clientKey;
std::string clientCert;
HeaderVec headers;
static bool validateHeaderName(StrView name)
{
return grpc_header_key_is_legal(
grpc_slice_from_static_buffer(name.data(), name.size()));
}
static bool validateHeaderValue(StrView value)
{
return grpc_header_nonbin_value_is_legal(
grpc_slice_from_static_buffer(value.data(), value.size()));
}
};
class TraceServiceClient {
public:
typedef otel_proto_trace::ExportTraceServiceRequest Request;
typedef otel_proto_trace::ExportTraceServiceResponse Response;
typedef otel_proto_trace::TraceService TraceService;
typedef std::function<void (Request, Response, grpc::Status)>
ResponseCb;
TraceServiceClient(const Target& target) : headers(target.headers)
{
std::shared_ptr<grpc::ChannelCredentials> creds;
if (target.ssl) {
grpc::SslCredentialsOptions options;
options.pem_root_certs = target.trustedCert;
options.pem_private_key = target.clientKey;
options.pem_cert_chain = target.clientCert;
creds = grpc::SslCredentials(options);
} else {
creds = grpc::InsecureChannelCredentials();
}
auto channel = grpc::CreateChannel(target.endpoint, creds);
channel->GetState(true); // trigger 'connecting' state
stub = TraceService::NewStub(channel);
}
void send(Request& req, ResponseCb cb)
{
std::unique_ptr<ActiveCall> call{new ActiveCall{}};
for (auto& header : headers) {
call->context.AddMetadata(header.first, header.second);
}
call->request = std::move(req);
call->cb = std::move(cb);
++pending;
// post actual RPC to worker thread to minimize load on caller
gpr_timespec past{};
call->sendAlarm.Set(&queue, past, call.release());
}
void run()
{
void* tag = NULL;
bool ok = false;
while (queue.Next(&tag, &ok)) {
assert(ok);
if (tag == &shutdownAlarm) {
shutdown = true;
} else {
std::unique_ptr<ActiveCall> call{(ActiveCall*)tag};
if (!call->sent) {
--pending;
call->responseReader = stub->AsyncExport(
&call->context, call->request, &queue);
call->sent = true;
call->responseReader->Finish(
&call->response, &call->status, call.get());
call.release();
} else {
call->cb(std::move(call->request),
std::move(call->response), std::move(call->status));
}
}
// It's not clear if gRPC guarantees any order for expired alarms,
// so we use 'pending' counter to ensure CQ shutdown happens last.
// https://github.com/grpc/grpc/issues/31398
if (shutdown && pending == 0) {
queue.Shutdown();
}
}
}
void stop()
{
gpr_timespec past{};
shutdownAlarm.Set(&queue, past, &shutdownAlarm);
}
private:
struct ActiveCall {
grpc::Alarm sendAlarm;
bool sent;
grpc::ClientContext context;
Request request;
Response response;
grpc::Status status;
std::unique_ptr<grpc::ClientAsyncResponseReader<Response>>
responseReader;
ResponseCb cb;
};
Target::HeaderVec headers;
std::unique_ptr<TraceService::Stub> stub;
grpc::CompletionQueue queue;
grpc::Alarm shutdownAlarm;
std::atomic<int> pending{0};
bool shutdown{false};
};