|
|
|
@ -35,7 +35,8 @@ |
|
|
|
|
|
|
|
|
|
namespace grpc_core { |
|
|
|
|
|
|
|
|
|
struct TraceEvent { |
|
|
|
|
class TraceEvent { |
|
|
|
|
public: |
|
|
|
|
TraceEvent(grpc_slice data, grpc_error* error, |
|
|
|
|
grpc_connectivity_state connectivity_state, |
|
|
|
|
ChannelTracer* referenced_tracer) |
|
|
|
@ -46,6 +47,10 @@ struct TraceEvent { |
|
|
|
|
referenced_tracer_ = referenced_tracer ? referenced_tracer->Ref() : nullptr; |
|
|
|
|
time_created_ = gpr_now(GPR_CLOCK_REALTIME); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
friend class ChannelTracer; |
|
|
|
|
friend class ChannelTracerRenderer; |
|
|
|
|
grpc_slice data_; |
|
|
|
|
grpc_error* error_; |
|
|
|
|
gpr_timespec time_created_; |
|
|
|
@ -138,8 +143,50 @@ static char* fmt_time(gpr_timespec tm) { |
|
|
|
|
return full_time_str; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Helper class that is responsible for walking the tree of ChannelTracer
|
|
|
|
|
// objects and rendering the trace as JSON according to:
|
|
|
|
|
// https://github.com/grpc/proposal/pull/7
|
|
|
|
|
|
|
|
|
|
// The rendered JSON should be of this format:
|
|
|
|
|
// {
|
|
|
|
|
// "channelData": {
|
|
|
|
|
// "numNodesLogged": number,
|
|
|
|
|
// "startTime": timestamp string,
|
|
|
|
|
// "nodes": [
|
|
|
|
|
// {
|
|
|
|
|
// "uuid": string,
|
|
|
|
|
// "data": string,
|
|
|
|
|
// "error": string,
|
|
|
|
|
// "time": timestamp string,
|
|
|
|
|
// // can only be one of the states in connectivity_state.h
|
|
|
|
|
// "state": enum string,
|
|
|
|
|
// // uuid of referenced subchannel
|
|
|
|
|
// "subchannel_uuid": string
|
|
|
|
|
// },
|
|
|
|
|
// ]
|
|
|
|
|
// },
|
|
|
|
|
// "numSubchannelsSeen": number,
|
|
|
|
|
// "subchannelData": [
|
|
|
|
|
// {
|
|
|
|
|
// "uuid": string,
|
|
|
|
|
// "numNodesLogged": number,
|
|
|
|
|
// "startTime": timestamp string,
|
|
|
|
|
// "nodes": [
|
|
|
|
|
// {
|
|
|
|
|
// "data": string,
|
|
|
|
|
// "error": string,
|
|
|
|
|
// "time": timestamp string,
|
|
|
|
|
// "state": enum string,
|
|
|
|
|
// },
|
|
|
|
|
// ]
|
|
|
|
|
// },
|
|
|
|
|
// ]
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
class ChannelTracerRenderer { |
|
|
|
|
public: |
|
|
|
|
// If recursive==true, then the entire tree of trace will be rendered.
|
|
|
|
|
// If not, then only the top level data will be.
|
|
|
|
|
ChannelTracerRenderer(ChannelTracer* tracer, bool recursive) |
|
|
|
|
: current_tracer_(tracer), |
|
|
|
|
recursive_(recursive), |
|
|
|
@ -147,17 +194,20 @@ class ChannelTracerRenderer { |
|
|
|
|
size_(0), |
|
|
|
|
cap_(0) {} |
|
|
|
|
|
|
|
|
|
// Renders the trace and returns an allocated char* with the formatted JSON
|
|
|
|
|
char* Run() { |
|
|
|
|
grpc_json* json = grpc_json_create(GRPC_JSON_OBJECT); |
|
|
|
|
AddSeenTracer(current_tracer_); |
|
|
|
|
RecursivelyPopulateJson(json); |
|
|
|
|
gpr_free(seen_tracers_); |
|
|
|
|
char* json_str = grpc_json_dump_to_string(json, 1); |
|
|
|
|
char* json_str = grpc_json_dump_to_string(json, 0); |
|
|
|
|
grpc_json_destroy(json); |
|
|
|
|
return json_str; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
// tracks that a tracer has already been rendered to avoid infinite
|
|
|
|
|
// recursion.
|
|
|
|
|
void AddSeenTracer(ChannelTracer* newly_seen) { |
|
|
|
|
if (size_ >= cap_) { |
|
|
|
|
cap_ = GPR_MAX(5 * sizeof(newly_seen), 3 * cap_ / 2); |
|
|
|
@ -166,6 +216,7 @@ class ChannelTracerRenderer { |
|
|
|
|
seen_tracers_[size_++] = newly_seen; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Checks if a tracer has already been seen.
|
|
|
|
|
bool TracerAlreadySeen(ChannelTracer* tracer) { |
|
|
|
|
for (size_t i = 0; i < size_; ++i) { |
|
|
|
|
if (seen_tracers_[i] == tracer) return true; |
|
|
|
@ -173,6 +224,8 @@ class ChannelTracerRenderer { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Recursively fills up json by walking over all of the trace of
|
|
|
|
|
// current_tracer_.
|
|
|
|
|
void RecursivelyPopulateJson(grpc_json* json) { |
|
|
|
|
grpc_json* channel_data = grpc_json_create_child( |
|
|
|
|
nullptr, json, "channelData", nullptr, GRPC_JSON_OBJECT, false); |
|
|
|
@ -251,8 +304,14 @@ class ChannelTracerRenderer { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Tracks the current tracer we are rendering as we walk the tree of tracers.
|
|
|
|
|
ChannelTracer* current_tracer_; |
|
|
|
|
|
|
|
|
|
// If true, we will render the data of all of this tracer's children.
|
|
|
|
|
bool recursive_; |
|
|
|
|
|
|
|
|
|
// These members are used to track tracers we have already rendered. This is
|
|
|
|
|
// a dynamically growing array that is deallocated when the rendering is done.
|
|
|
|
|
ChannelTracer** seen_tracers_; |
|
|
|
|
size_t size_; |
|
|
|
|
size_t cap_; |
|
|
|
|