Classify the tracer object

reviewable/pr13883/r1
ncteisen 7 years ago
parent b04efac6a5
commit 6572ce2c4a
  1. 2
      src/core/ext/filters/client_channel/subchannel.cc
  2. 370
      src/core/lib/channel/channel_tracer.cc
  3. 84
      src/core/lib/channel/channel_tracer.h
  4. 2
      src/core/lib/support/object_registry.cc
  5. 17
      src/core/lib/surface/channel.cc
  6. 214
      test/core/channel/channel_tracer_test.cc

@ -137,7 +137,7 @@ struct grpc_subchannel {
/** our alarm */ /** our alarm */
grpc_timer alarm; grpc_timer alarm;
grpc_channel_tracer* tracer; grpc_core::ChannelTracer* tracer;
}; };
struct grpc_subchannel_call { struct grpc_subchannel_call {

@ -32,6 +32,8 @@
#include "src/core/lib/surface/channel.h" #include "src/core/lib/surface/channel.h"
#include "src/core/lib/transport/connectivity_state.h" #include "src/core/lib/transport/connectivity_state.h"
namespace grpc_core {
grpc_core::DebugOnlyTraceFlag grpc_trace_channel_tracer_refcount( grpc_core::DebugOnlyTraceFlag grpc_trace_channel_tracer_refcount(
false, "channel_tracer_refcount"); false, "channel_tracer_refcount");
@ -44,116 +46,55 @@ typedef struct grpc_trace_node {
struct grpc_trace_node* next; struct grpc_trace_node* next;
// the tracer object for the (sub)channel that this trace node refers to. // the tracer object for the (sub)channel that this trace node refers to.
grpc_channel_tracer* referenced_tracer; ChannelTracer* referenced_tracer;
} grpc_trace_node; } grpc_trace_node;
/* the channel tracing object */ ChannelTracer::ChannelTracer(size_t max_nodes)
struct grpc_channel_tracer { : num_nodes_logged(0),
gpr_refcount refs; list_size(0),
gpr_mu tracer_mu; max_list_size(max_nodes),
intptr_t channel_uuid; head_trace(0),
uint64_t num_nodes_logged; tail_trace(0) {
size_t list_size; gpr_mu_init(&tracer_mu);
size_t max_list_size; gpr_ref_init(&refs, 1);
grpc_trace_node* head_trace; channel_uuid = grpc_object_registry_register_object(
grpc_trace_node* tail_trace; this, GRPC_OBJECT_REGISTRY_CHANNEL_TRACER);
gpr_timespec time_created; max_list_size = max_nodes;
}; time_created = gpr_now(GPR_CLOCK_REALTIME);
#ifndef NDEBUG
grpc_channel_tracer* grpc_channel_tracer_create(size_t max_nodes,
const char* file, int line,
const char* func) {
#else
grpc_channel_tracer* grpc_channel_tracer_create(size_t max_nodes) {
#endif
grpc_channel_tracer* tracer = static_cast<grpc_channel_tracer*>(
gpr_zalloc(sizeof(grpc_channel_tracer)));
gpr_mu_init(&tracer->tracer_mu);
gpr_ref_init(&tracer->refs, 1);
#ifndef NDEBUG
if (grpc_trace_channel_tracer_refcount.enabled()) {
gpr_log(GPR_DEBUG, "%p create [%s:%d %s]", tracer, file, line, func);
}
#endif
tracer->channel_uuid = grpc_object_registry_register_object(
tracer, GRPC_OBJECT_REGISTRY_CHANNEL_TRACER);
tracer->max_list_size = max_nodes;
tracer->time_created = gpr_now(GPR_CLOCK_REALTIME);
return tracer;
} }
#ifndef NDEBUG ChannelTracer* ChannelTracer::Ref() {
grpc_channel_tracer* grpc_channel_tracer_ref(grpc_channel_tracer* tracer, gpr_ref(&refs);
const char* file, int line, return this;
const char* func) {
if (!tracer) return tracer;
if (grpc_trace_channel_tracer_refcount.enabled()) {
gpr_log(GPR_DEBUG, "%p: %" PRIdPTR " -> %" PRIdPTR " [%s:%d %s]", tracer,
gpr_atm_no_barrier_load(&tracer->refs.count),
gpr_atm_no_barrier_load(&tracer->refs.count) + 1, file, line, func);
}
gpr_ref(&tracer->refs);
return tracer;
} }
#else
grpc_channel_tracer* grpc_channel_tracer_ref(grpc_channel_tracer* tracer) {
if (!tracer) return tracer;
gpr_ref(&tracer->refs);
return tracer;
}
#endif
static void free_node(grpc_trace_node* node) { static void free_node(grpc_trace_node* node) {
GRPC_ERROR_UNREF(node->error); GRPC_ERROR_UNREF(node->error);
GRPC_CHANNEL_TRACER_UNREF(node->referenced_tracer); if (node->referenced_tracer) {
node->referenced_tracer->Unref();
}
grpc_slice_unref_internal(node->data); grpc_slice_unref_internal(node->data);
gpr_free(node); gpr_free(node);
} }
static void grpc_channel_tracer_destroy(grpc_channel_tracer* tracer) { void ChannelTracer::Unref() {
grpc_trace_node* it = tracer->head_trace; if (gpr_unref(&refs)) {
while (it != nullptr) { grpc_trace_node* it = head_trace;
grpc_trace_node* to_free = it; while (it != nullptr) {
it = it->next; grpc_trace_node* to_free = it;
free_node(to_free); it = it->next;
} free_node(to_free);
gpr_mu_destroy(&tracer->tracer_mu); }
gpr_free(tracer); gpr_mu_destroy(&tracer_mu);
}
#ifndef NDEBUG
void grpc_channel_tracer_unref(grpc_channel_tracer* tracer, const char* file,
int line, const char* func) {
if (!tracer) return;
if (grpc_trace_channel_tracer_refcount.enabled()) {
gpr_log(GPR_DEBUG, "%p: %" PRIdPTR " -> %" PRIdPTR " [%s:%d %s]", tracer,
gpr_atm_no_barrier_load(&tracer->refs.count),
gpr_atm_no_barrier_load(&tracer->refs.count) - 1, file, line, func);
}
if (gpr_unref(&tracer->refs)) {
grpc_channel_tracer_destroy(tracer);
}
}
#else
void grpc_channel_tracer_unref(grpc_channel_tracer* tracer) {
if (!tracer) return;
if (gpr_unref(&tracer->refs)) {
grpc_channel_tracer_destroy(tracer);
} }
} }
#endif
intptr_t grpc_channel_tracer_get_uuid(grpc_channel_tracer* tracer) { intptr_t ChannelTracer::GetUuid() { return channel_uuid; }
return tracer->channel_uuid;
}
void grpc_channel_tracer_add_trace(grpc_channel_tracer* tracer, grpc_slice data, void ChannelTracer::AddTrace(grpc_slice data, grpc_error* error,
grpc_error* error, grpc_connectivity_state connectivity_state,
grpc_connectivity_state connectivity_state, ChannelTracer* referenced_tracer) {
grpc_channel_tracer* referenced_tracer) { ++num_nodes_logged;
if (!tracer) return;
++tracer->num_nodes_logged;
// create and fill up the new node // create and fill up the new node
grpc_trace_node* new_trace_node = grpc_trace_node* new_trace_node =
static_cast<grpc_trace_node*>(gpr_malloc(sizeof(grpc_trace_node))); static_cast<grpc_trace_node*>(gpr_malloc(sizeof(grpc_trace_node)));
@ -163,23 +104,23 @@ void grpc_channel_tracer_add_trace(grpc_channel_tracer* tracer, grpc_slice data,
new_trace_node->connectivity_state = connectivity_state; new_trace_node->connectivity_state = connectivity_state;
new_trace_node->next = nullptr; new_trace_node->next = nullptr;
new_trace_node->referenced_tracer = new_trace_node->referenced_tracer =
GRPC_CHANNEL_TRACER_REF(referenced_tracer); (referenced_tracer) ? referenced_tracer->Ref() : nullptr;
// first node case // first node case
if (tracer->head_trace == nullptr) { if (head_trace == nullptr) {
tracer->head_trace = tracer->tail_trace = new_trace_node; head_trace = tail_trace = new_trace_node;
} }
// regular node add case // regular node add case
else { else {
tracer->tail_trace->next = new_trace_node; tail_trace->next = new_trace_node;
tracer->tail_trace = tracer->tail_trace->next; tail_trace = tail_trace->next;
} }
++tracer->list_size; ++list_size;
// maybe garbage collect the end // maybe garbage collect the end
if (tracer->list_size > tracer->max_list_size) { if (list_size > max_list_size) {
grpc_trace_node* to_free = tracer->head_trace; grpc_trace_node* to_free = head_trace;
tracer->head_trace = tracer->head_trace->next; head_trace = head_trace->next;
free_node(to_free); free_node(to_free);
--tracer->list_size; --list_size;
} }
} }
@ -193,135 +134,138 @@ static char* fmt_time(gpr_timespec tm) {
return full_time_str; return full_time_str;
} }
typedef struct seen_tracers { class ChannelTracerRenderer {
grpc_channel_tracer** tracers; public:
size_t size; ChannelTracerRenderer(ChannelTracer* tracer, bool recursive)
size_t cap; : current_tracer_(tracer),
} seen_tracers; recursive_(recursive),
seen_tracers_(nullptr),
size_(0),
cap_(0) {}
static void seen_tracers_add(seen_tracers* tracker, char* Run() {
grpc_channel_tracer* tracer) { grpc_json* json = grpc_json_create(GRPC_JSON_OBJECT);
if (tracker->size >= tracker->cap) { AddSeenTracer(current_tracer_);
tracker->cap = GPR_MAX(5 * sizeof(tracer), 3 * tracker->cap / 2); RecursivelyPopulateJson(json);
tracker->tracers = gpr_free(seen_tracers_);
(grpc_channel_tracer**)gpr_realloc(tracker->tracers, tracker->cap); char* json_str = grpc_json_dump_to_string(json, 1);
grpc_json_destroy(json);
return json_str;
} }
tracker->tracers[tracker->size++] = tracer;
}
static bool seen_tracers_check(seen_tracers* tracker, private:
grpc_channel_tracer* tracer) { void AddSeenTracer(ChannelTracer* newly_seen) {
for (size_t i = 0; i < tracker->size; ++i) { if (size_ >= cap_) {
if (tracker->tracers[i] == tracer) return true; cap_ = GPR_MAX(5 * sizeof(newly_seen), 3 * cap_ / 2);
seen_tracers_ = (ChannelTracer**)gpr_realloc(seen_tracers_, cap_);
}
seen_tracers_[size_++] = newly_seen;
} }
return false;
}
static void recursively_populate_json(grpc_channel_tracer* tracer, bool TracerAlreadySeen(ChannelTracer* tracer) {
seen_tracers* tracker, grpc_json* json, for (size_t i = 0; i < size_; ++i) {
bool recursive); if (seen_tracers_[i] == tracer) return true;
static void populate_node_data(grpc_trace_node* node, seen_tracers* tracker,
grpc_json* json, grpc_json* children) {
grpc_json* child = nullptr;
child = grpc_json_create_child(child, json, "data",
grpc_slice_to_c_string(node->data),
GRPC_JSON_STRING, true);
if (node->error != GRPC_ERROR_NONE) {
child = grpc_json_create_child(child, json, "error",
gpr_strdup(grpc_error_string(node->error)),
GRPC_JSON_STRING, true);
}
child =
grpc_json_create_child(child, json, "time", fmt_time(node->time_created),
GRPC_JSON_STRING, true);
child = grpc_json_create_child(
child, json, "state",
grpc_connectivity_state_name(node->connectivity_state), GRPC_JSON_STRING,
false);
if (node->referenced_tracer != nullptr) {
char* uuid_str;
gpr_asprintf(&uuid_str, "%" PRIdPTR, node->referenced_tracer->channel_uuid);
child = grpc_json_create_child(child, json, "uuid", uuid_str,
GRPC_JSON_NUMBER, true);
if (children && !seen_tracers_check(tracker, node->referenced_tracer)) {
grpc_json* referenced_tracer = grpc_json_create_child(
nullptr, children, nullptr, nullptr, GRPC_JSON_OBJECT, false);
recursively_populate_json(node->referenced_tracer, tracker,
referenced_tracer, true);
} }
return false;
} }
}
static void populate_node_list_data(grpc_channel_tracer* tracer, void RecursivelyPopulateJson(grpc_json* json) {
seen_tracers* tracker, grpc_json* nodes, grpc_json* channel_data = grpc_json_create_child(
grpc_json* children) { nullptr, json, "channelData", nullptr, GRPC_JSON_OBJECT, false);
grpc_json* child = nullptr; grpc_json* children = nullptr;
grpc_trace_node* it = tracer->head_trace; if (recursive_) {
while (it != nullptr) { children = grpc_json_create_child(channel_data, json, "children", nullptr,
child = grpc_json_create_child(child, nodes, nullptr, nullptr, GRPC_JSON_ARRAY, false);
GRPC_JSON_OBJECT, false); }
populate_node_data(it, tracker, child, children); PopulateTracer(channel_data, children);
it = it->next;
} }
}
static void populate_tracer_data(grpc_channel_tracer* tracer, void PopulateTracer(grpc_json* channel_data, grpc_json* children) {
seen_tracers* tracker, grpc_json* channel_data, grpc_json* child = nullptr;
grpc_json* children) {
grpc_json* child = nullptr;
char* uuid_str; char* uuid_str;
gpr_asprintf(&uuid_str, "%" PRIdPTR, tracer->channel_uuid); gpr_asprintf(&uuid_str, "%" PRIdPTR, current_tracer_->channel_uuid);
child = grpc_json_create_child(child, channel_data, "uuid", uuid_str, child = grpc_json_create_child(child, channel_data, "uuid", uuid_str,
GRPC_JSON_NUMBER, true); GRPC_JSON_NUMBER, true);
char* num_nodes_logged_str; char* num_nodes_logged_str;
gpr_asprintf(&num_nodes_logged_str, "%" PRId64, tracer->num_nodes_logged); gpr_asprintf(&num_nodes_logged_str, "%" PRId64,
child = grpc_json_create_child(child, channel_data, "numNodesLogged", current_tracer_->num_nodes_logged);
num_nodes_logged_str, GRPC_JSON_NUMBER, true); child =
child = grpc_json_create_child(child, channel_data, "startTime", grpc_json_create_child(child, channel_data, "numNodesLogged",
fmt_time(tracer->time_created), num_nodes_logged_str, GRPC_JSON_NUMBER, true);
GRPC_JSON_STRING, true); child = grpc_json_create_child(child, channel_data, "startTime",
child = grpc_json_create_child(child, channel_data, "nodes", nullptr, fmt_time(current_tracer_->time_created),
GRPC_JSON_ARRAY, false); GRPC_JSON_STRING, true);
populate_node_list_data(tracer, tracker, child, children); child = grpc_json_create_child(child, channel_data, "nodes", nullptr,
} GRPC_JSON_ARRAY, false);
PopulateNodeList(child, children);
static void recursively_populate_json(grpc_channel_tracer* tracer,
seen_tracers* tracker, grpc_json* json,
bool recursive) {
grpc_json* channel_data = grpc_json_create_child(
nullptr, json, "channelData", nullptr, GRPC_JSON_OBJECT, false);
grpc_json* children = nullptr;
if (recursive) {
children = grpc_json_create_child(channel_data, json, "children", nullptr,
GRPC_JSON_ARRAY, false);
} }
seen_tracers_add(tracker, tracer);
populate_tracer_data(tracer, tracker, channel_data, children);
}
char* grpc_channel_tracer_render_trace(grpc_channel_tracer* tracer,
bool recursive) {
grpc_json* json = grpc_json_create(GRPC_JSON_OBJECT);
seen_tracers tracker; void PopulateNodeList(grpc_json* nodes, grpc_json* children) {
memset(&tracker, 0, sizeof(tracker)); grpc_json* child = nullptr;
grpc_trace_node* it = current_tracer_->head_trace;
while (it != nullptr) {
child = grpc_json_create_child(child, nodes, nullptr, nullptr,
GRPC_JSON_OBJECT, false);
PopulateNode(it, child, children);
it = it->next;
}
}
recursively_populate_json(tracer, &tracker, json, recursive); void PopulateNode(grpc_trace_node* node, grpc_json* json,
grpc_json* children) {
grpc_json* child = nullptr;
child = grpc_json_create_child(child, json, "data",
grpc_slice_to_c_string(node->data),
GRPC_JSON_STRING, true);
if (node->error != GRPC_ERROR_NONE) {
child = grpc_json_create_child(child, json, "error",
gpr_strdup(grpc_error_string(node->error)),
GRPC_JSON_STRING, true);
}
child = grpc_json_create_child(child, json, "time",
fmt_time(node->time_created),
GRPC_JSON_STRING, true);
child = grpc_json_create_child(
child, json, "state",
grpc_connectivity_state_name(node->connectivity_state),
GRPC_JSON_STRING, false);
if (node->referenced_tracer != nullptr) {
char* uuid_str;
gpr_asprintf(&uuid_str, "%" PRIdPTR,
node->referenced_tracer->channel_uuid);
child = grpc_json_create_child(child, json, "uuid", uuid_str,
GRPC_JSON_NUMBER, true);
if (children && !TracerAlreadySeen(node->referenced_tracer)) {
grpc_json* referenced_tracer = grpc_json_create_child(
nullptr, children, nullptr, nullptr, GRPC_JSON_OBJECT, false);
AddSeenTracer(node->referenced_tracer);
ChannelTracer* saved = current_tracer_;
current_tracer_ = node->referenced_tracer;
RecursivelyPopulateJson(referenced_tracer);
current_tracer_ = saved;
}
}
}
gpr_free(tracker.tracers); ChannelTracer* current_tracer_;
bool recursive_;
ChannelTracer** seen_tracers_;
size_t size_;
size_t cap_;
};
char* json_str = grpc_json_dump_to_string(json, 1); char* ChannelTracer::RenderTrace(bool recursive) {
grpc_json_destroy(json); ChannelTracerRenderer renderer(this, recursive);
return json_str; return renderer.Run();
} }
char* grpc_channel_tracer_get_trace(intptr_t uuid, bool recursive) { char* ChannelTracer::GetChannelTraceFromUuid(intptr_t uuid, bool recursive) {
void* object; void* object;
grpc_object_registry_type type = grpc_object_registry_type type =
grpc_object_registry_get_object(uuid, &object); grpc_object_registry_get_object(uuid, &object);
GPR_ASSERT(type == GRPC_OBJECT_REGISTRY_CHANNEL_TRACER); GPR_ASSERT(type == GRPC_OBJECT_REGISTRY_CHANNEL_TRACER);
return grpc_channel_tracer_render_trace( return static_cast<ChannelTracer*>(object)->RenderTrace(recursive);
static_cast<grpc_channel_tracer*>(object), recursive);
} }
} // namespace grpc_core

@ -23,58 +23,52 @@
#include "src/core/lib/iomgr/error.h" #include "src/core/lib/iomgr/error.h"
#include "src/core/lib/json/json.h" #include "src/core/lib/json/json.h"
/* Forward declaration */ namespace grpc_core {
typedef struct grpc_channel_tracer grpc_channel_tracer;
extern grpc_core::DebugOnlyTraceFlag grpc_trace_channel_tracer_refcount; extern grpc_core::DebugOnlyTraceFlag grpc_trace_channel_tracer_refcount;
/* Creates a new tracer. The caller owns a reference to the returned tracer. */ typedef struct grpc_trace_node grpc_trace_node;
#ifndef NDEBUG
grpc_channel_tracer* grpc_channel_tracer_create(size_t max_nodes,
const char* file, int line,
const char* func);
#define GRPC_CHANNEL_TRACER_CREATE(max_nodes) \
grpc_channel_tracer_create(max_nodes, __FILE__, __LINE__, __func__)
#else
grpc_channel_tracer* grpc_channel_tracer_create(size_t max_nodes);
#define GRPC_CHANNEL_TRACER_CREATE(max_nodes) \
grpc_channel_tracer_create(max_nodes)
#endif
#ifndef NDEBUG class ChannelTracer {
grpc_channel_tracer* grpc_channel_tracer_ref(grpc_channel_tracer* tracer, public:
const char* file, int line, ChannelTracer(size_t max_nodes);
const char* func); ~ChannelTracer() {}
void grpc_channel_tracer_unref(grpc_channel_tracer* tracer, const char* file,
int line, const char* func);
#define GRPC_CHANNEL_TRACER_REF(tracer) \
grpc_channel_tracer_ref(tracer, __FILE__, __LINE__, __func__)
#define GRPC_CHANNEL_TRACER_UNREF(tracer) \
grpc_channel_tracer_unref(tracer, __FILE__, __LINE__, __func__)
#else
grpc_channel_tracer* grpc_channel_tracer_ref(grpc_channel_tracer* tracer);
void grpc_channel_tracer_unref(grpc_channel_tracer* tracer);
#define GRPC_CHANNEL_TRACER_REF(tracer) grpc_channel_tracer_ref(tracer)
#define GRPC_CHANNEL_TRACER_UNREF(tracer) grpc_channel_tracer_unref(tracer)
#endif
/* returns the tracers uuid */ // TODO(ncteisen): incorporate RefCounted class
intptr_t grpc_channel_tracer_get_uuid(grpc_channel_tracer* tracer); ChannelTracer* Ref();
void Unref();
/* Adds a new trace node to the tracing object */ /* returns the tracers uuid */
void grpc_channel_tracer_add_trace(grpc_channel_tracer* tracer, grpc_slice data, intptr_t GetUuid();
grpc_error* error,
grpc_connectivity_state connectivity_state,
grpc_channel_tracer* subchannel);
/* Returns the tracing data rendered as a grpc json string. /* Adds a new trace node to the tracing object */
The string is owned by the caller and must be freed. If recursive void AddTrace(grpc_slice data, grpc_error* error,
is true, then the string will include the recursive trace for all grpc_connectivity_state connectivity_state,
subtracing objects. */ ChannelTracer* subchannel);
char* grpc_channel_tracer_render_trace(grpc_channel_tracer* tracer,
bool recursive); /* Returns the tracing data rendered as a grpc json string.
/* util functions that perform the uuid -> tracer step for you, and then The string is owned by the caller and must be freed. If recursive
is true, then the string will include the recursive trace for all
subtracing objects. */
char* RenderTrace(bool recursive);
/* util functions that perform the uuid -> tracer step for you, and then
returns the trace for the uuid given. */ returns the trace for the uuid given. */
char* grpc_channel_tracer_get_trace(intptr_t uuid, bool recursive); static char* GetChannelTraceFromUuid(intptr_t uuid, bool recursive);
private:
friend class ChannelTracerRenderer;
gpr_refcount refs;
gpr_mu tracer_mu;
intptr_t channel_uuid;
uint64_t num_nodes_logged;
size_t list_size;
size_t max_list_size;
grpc_trace_node* head_trace;
grpc_trace_node* tail_trace;
gpr_timespec time_created;
};
} // namespace grpc_core
#endif /* GRPC_CORE_LIB_CHANNEL_CHANNEL_TRACER_H */ #endif /* GRPC_CORE_LIB_CHANNEL_CHANNEL_TRACER_H */

@ -37,7 +37,7 @@ typedef struct {
static void destroy_intptr(void* not_used, void* user_data) {} static void destroy_intptr(void* not_used, void* user_data) {}
static void* copy_intptr(void* key, void* user_data) { return key; } static void* copy_intptr(void* key, void* user_data) { return key; }
static long compare_intptr(void* key1, void* key2, void* user_data) { static long compare_intptr(void* key1, void* key2, void* user_data) {
return key1 > key2; return (intptr_t)key1 - (intptr_t)key2;
} }
static void destroy_tracker(void* tracker, void* user_data) { static void destroy_tracker(void* tracker, void* user_data) {

@ -32,6 +32,7 @@
#include "src/core/lib/debug/stats.h" #include "src/core/lib/debug/stats.h"
#include "src/core/lib/iomgr/iomgr.h" #include "src/core/lib/iomgr/iomgr.h"
#include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/support/memory.h"
#include "src/core/lib/support/object_registry.h" #include "src/core/lib/support/object_registry.h"
#include "src/core/lib/support/string.h" #include "src/core/lib/support/string.h"
#include "src/core/lib/surface/api_trace.h" #include "src/core/lib/surface/api_trace.h"
@ -63,7 +64,7 @@ struct grpc_channel {
gpr_mu registered_call_mu; gpr_mu registered_call_mu;
registered_call* registered_calls; registered_call* registered_calls;
grpc_channel_tracer* tracer; grpc_core::ChannelTracer* tracer;
char* target; char* target;
}; };
@ -202,23 +203,21 @@ grpc_channel* grpc_channel_create_with_builder(
size_t max_nodes = size_t max_nodes =
(size_t)grpc_channel_arg_get_integer(&args->args[i], options); (size_t)grpc_channel_arg_get_integer(&args->args[i], options);
if (max_nodes > 0) { if (max_nodes > 0) {
channel->tracer = GRPC_CHANNEL_TRACER_CREATE(max_nodes); channel->tracer = grpc_core::New<grpc_core::ChannelTracer>(
channel->uuid = grpc_channel_tracer_get_uuid(channel->tracer); max_nodes); // TODO(ncteisen): leaky yo
channel->uuid = channel->tracer->GetUuid();
} }
} }
} }
grpc_channel_args_destroy(args); grpc_channel_args_destroy(args);
grpc_channel_tracer_add_trace( channel->tracer->AddTrace(grpc_slice_from_static_string("Channel created"),
channel->tracer, grpc_slice_from_static_string("Channel created"), GRPC_ERROR_NONE, GRPC_CHANNEL_IDLE, nullptr);
GRPC_ERROR_NONE, GRPC_CHANNEL_IDLE, nullptr);
return channel; return channel;
} }
char* grpc_channel_get_trace(grpc_channel* channel, bool recursive) { char* grpc_channel_get_trace(grpc_channel* channel, bool recursive) {
return channel->tracer return channel->tracer ? channel->tracer->RenderTrace(recursive) : nullptr;
? grpc_channel_tracer_render_trace(channel->tracer, recursive)
: nullptr;
} }
intptr_t grpc_channel_get_uuid(grpc_channel* channel) { return channel->uuid; } intptr_t grpc_channel_get_uuid(grpc_channel* channel) { return channel->uuid; }

@ -29,18 +29,19 @@
#include "test/core/util/channel_tracing_utils.h" #include "test/core/util/channel_tracing_utils.h"
#include "test/core/util/test_config.h" #include "test/core/util/test_config.h"
static void add_simple_trace(grpc_channel_tracer* tracer) { using grpc_core::ChannelTracer;
grpc_channel_tracer_add_trace(tracer,
grpc_slice_from_static_string("simple trace"), static void add_simple_trace(ChannelTracer* tracer) {
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error"), tracer->AddTrace(grpc_slice_from_static_string("simple trace"),
GRPC_CHANNEL_READY, nullptr); GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error"),
GRPC_CHANNEL_READY, nullptr);
} }
// checks for the existence of all the required members of the tracer. // checks for the existence of all the required members of the tracer.
static void validate_tracer(grpc_channel_tracer* tracer, static void validate_tracer(ChannelTracer* tracer,
size_t expected_num_nodes_logged, size_t expected_num_nodes_logged,
size_t max_nodes) { size_t max_nodes) {
char* json_str = grpc_channel_tracer_render_trace(tracer, true); char* json_str = tracer->RenderTrace(true);
grpc_json* json = grpc_json_parse_string(json_str); grpc_json* json = grpc_json_parse_string(json_str);
validate_channel_data(json, expected_num_nodes_logged, validate_channel_data(json, expected_num_nodes_logged,
GPR_MIN(expected_num_nodes_logged, max_nodes)); GPR_MIN(expected_num_nodes_logged, max_nodes));
@ -48,10 +49,20 @@ static void validate_tracer(grpc_channel_tracer* tracer,
gpr_free(json_str); gpr_free(json_str);
} }
static void validate_tracer_data_matches_uuid_lookup(ChannelTracer* tracer) {
intptr_t uuid = tracer->GetUuid();
char* tracer_json_str = tracer->RenderTrace(true);
char* uuid_lookup_json_str =
ChannelTracer::GetChannelTraceFromUuid(uuid, true);
strcmp(tracer_json_str, uuid_lookup_json_str);
gpr_free(tracer_json_str);
gpr_free(uuid_lookup_json_str);
}
// ensures the tracer has the correct number of children tracers. // ensures the tracer has the correct number of children tracers.
static void validate_children(grpc_channel_tracer* tracer, static void validate_children(ChannelTracer* tracer,
size_t expected_num_children) { size_t expected_num_children) {
char* json_str = grpc_channel_tracer_render_trace(tracer, true); char* json_str = tracer->RenderTrace(true);
grpc_json* json = grpc_json_parse_string(json_str); grpc_json* json = grpc_json_parse_string(json_str);
validate_json_array_size(json, "children", expected_num_children); validate_json_array_size(json, "children", expected_num_children);
grpc_json_destroy(json); grpc_json_destroy(json);
@ -59,28 +70,29 @@ static void validate_children(grpc_channel_tracer* tracer,
} }
static void test_basic_channel_tracing(size_t max_nodes) { static void test_basic_channel_tracing(size_t max_nodes) {
grpc_channel_tracer* tracer = GRPC_CHANNEL_TRACER_CREATE(max_nodes);
grpc_core::ExecCtx exec_ctx; grpc_core::ExecCtx exec_ctx;
add_simple_trace(tracer); ChannelTracer tracer(max_nodes);
add_simple_trace(tracer); add_simple_trace(&tracer);
grpc_channel_tracer_add_trace( add_simple_trace(&tracer);
tracer, grpc_slice_from_static_string("trace three"), validate_tracer_data_matches_uuid_lookup(&tracer);
tracer.AddTrace(
grpc_slice_from_static_string("trace three"),
grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error"), grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING("Error"),
GRPC_ERROR_INT_HTTP2_ERROR, 2), GRPC_ERROR_INT_HTTP2_ERROR, 2),
GRPC_CHANNEL_IDLE, nullptr); GRPC_CHANNEL_IDLE, nullptr);
grpc_channel_tracer_add_trace( tracer.AddTrace(grpc_slice_from_static_string("trace four"), GRPC_ERROR_NONE,
tracer, grpc_slice_from_static_string("trace four"), GRPC_ERROR_NONE, GRPC_CHANNEL_SHUTDOWN, nullptr);
GRPC_CHANNEL_SHUTDOWN, nullptr); validate_tracer(&tracer, 4, max_nodes);
validate_tracer(tracer, 4, max_nodes); add_simple_trace(&tracer);
add_simple_trace(tracer); add_simple_trace(&tracer);
add_simple_trace(tracer); validate_tracer(&tracer, 6, max_nodes);
validate_tracer(tracer, 6, max_nodes); add_simple_trace(&tracer);
add_simple_trace(tracer); add_simple_trace(&tracer);
add_simple_trace(tracer); add_simple_trace(&tracer);
add_simple_trace(tracer); add_simple_trace(&tracer);
add_simple_trace(tracer); validate_tracer(&tracer, 10, max_nodes);
validate_tracer(tracer, 10, max_nodes); validate_tracer_data_matches_uuid_lookup(&tracer);
GRPC_CHANNEL_TRACER_UNREF(tracer); tracer.Unref();
} }
static void test_basic_channel_sizing() { static void test_basic_channel_sizing() {
@ -93,43 +105,42 @@ static void test_basic_channel_sizing() {
} }
static void test_complex_channel_tracing(size_t max_nodes) { static void test_complex_channel_tracing(size_t max_nodes) {
grpc_channel_tracer* tracer = GRPC_CHANNEL_TRACER_CREATE(max_nodes);
grpc_core::ExecCtx exec_ctx; grpc_core::ExecCtx exec_ctx;
add_simple_trace(tracer); ChannelTracer tracer(max_nodes);
add_simple_trace(tracer); add_simple_trace(&tracer);
grpc_channel_tracer* sc1 = GRPC_CHANNEL_TRACER_CREATE(max_nodes); add_simple_trace(&tracer);
grpc_channel_tracer_add_trace( ChannelTracer sc1(max_nodes);
tracer, grpc_slice_from_static_string("subchannel one created"), tracer.AddTrace(grpc_slice_from_static_string("subchannel one created"),
GRPC_ERROR_NONE, GRPC_CHANNEL_IDLE, sc1); GRPC_ERROR_NONE, GRPC_CHANNEL_IDLE, &sc1);
validate_tracer(tracer, 3, max_nodes); validate_tracer(&tracer, 3, max_nodes);
add_simple_trace(sc1); add_simple_trace(&sc1);
add_simple_trace(sc1); add_simple_trace(&sc1);
add_simple_trace(sc1); add_simple_trace(&sc1);
validate_tracer(sc1, 3, max_nodes); validate_tracer(&sc1, 3, max_nodes);
add_simple_trace(sc1); add_simple_trace(&sc1);
add_simple_trace(sc1); add_simple_trace(&sc1);
add_simple_trace(sc1); add_simple_trace(&sc1);
validate_tracer(sc1, 6, max_nodes); validate_tracer(&sc1, 6, max_nodes);
add_simple_trace(tracer); add_simple_trace(&tracer);
add_simple_trace(tracer); add_simple_trace(&tracer);
validate_tracer(tracer, 5, max_nodes); validate_tracer(&tracer, 5, max_nodes);
grpc_channel_tracer* sc2 = GRPC_CHANNEL_TRACER_CREATE(max_nodes); validate_tracer_data_matches_uuid_lookup(&tracer);
grpc_channel_tracer_add_trace( ChannelTracer sc2(max_nodes);
tracer, grpc_slice_from_static_string("subchannel two created"), tracer.AddTrace(grpc_slice_from_static_string("subchannel two created"),
GRPC_ERROR_NONE, GRPC_CHANNEL_IDLE, sc2); GRPC_ERROR_NONE, GRPC_CHANNEL_IDLE, &sc2);
grpc_channel_tracer_add_trace( tracer.AddTrace(grpc_slice_from_static_string("subchannel one inactive"),
tracer, grpc_slice_from_static_string("subchannel one inactive"), GRPC_ERROR_NONE, GRPC_CHANNEL_IDLE, &sc1);
GRPC_ERROR_NONE, GRPC_CHANNEL_IDLE, sc1); validate_tracer(&tracer, 7, max_nodes);
validate_tracer(tracer, 7, max_nodes); add_simple_trace(&tracer);
add_simple_trace(tracer); add_simple_trace(&tracer);
add_simple_trace(tracer); add_simple_trace(&tracer);
add_simple_trace(tracer); add_simple_trace(&tracer);
add_simple_trace(tracer); add_simple_trace(&tracer);
add_simple_trace(tracer); add_simple_trace(&tracer);
add_simple_trace(tracer); // validate_tracer_data_matches_uuid_lookup(&tracer);
GRPC_CHANNEL_TRACER_UNREF(sc1); sc1.Unref();
GRPC_CHANNEL_TRACER_UNREF(sc2); sc2.Unref();
GRPC_CHANNEL_TRACER_UNREF(tracer); tracer.Unref();
} }
static void test_complex_channel_sizing() { static void test_complex_channel_sizing() {
@ -142,57 +153,52 @@ static void test_complex_channel_sizing() {
} }
static void test_delete_parent_first() { static void test_delete_parent_first() {
grpc_channel_tracer* tracer = GRPC_CHANNEL_TRACER_CREATE(3);
grpc_core::ExecCtx exec_ctx; grpc_core::ExecCtx exec_ctx;
add_simple_trace(tracer); ChannelTracer tracer(3);
add_simple_trace(tracer); add_simple_trace(&tracer);
grpc_channel_tracer* sc1 = GRPC_CHANNEL_TRACER_CREATE(3); add_simple_trace(&tracer);
grpc_channel_tracer_add_trace( ChannelTracer sc1(3);
tracer, grpc_slice_from_static_string("subchannel one created"), tracer.AddTrace(grpc_slice_from_static_string("subchannel one created"),
GRPC_ERROR_NONE, GRPC_CHANNEL_IDLE, sc1); GRPC_ERROR_NONE, GRPC_CHANNEL_IDLE, &sc1);
// this will cause the tracer destructor to run. // this will cause the tracer destructor to run.
GRPC_CHANNEL_TRACER_UNREF(tracer); tracer.Unref();
GRPC_CHANNEL_TRACER_UNREF(sc1); sc1.Unref();
} }
static void test_nesting() { static void test_nesting() {
grpc_channel_tracer* tracer = GRPC_CHANNEL_TRACER_CREATE(10);
grpc_core::ExecCtx exec_ctx; grpc_core::ExecCtx exec_ctx;
add_simple_trace(tracer); ChannelTracer tracer(10);
add_simple_trace(tracer); add_simple_trace(&tracer);
grpc_channel_tracer* sc1 = GRPC_CHANNEL_TRACER_CREATE(5); add_simple_trace(&tracer);
grpc_channel_tracer_add_trace( ChannelTracer sc1(5);
tracer, grpc_slice_from_static_string("subchannel one created"), tracer.AddTrace(grpc_slice_from_static_string("subchannel one created"),
GRPC_ERROR_NONE, GRPC_CHANNEL_IDLE, sc1); GRPC_ERROR_NONE, GRPC_CHANNEL_IDLE, &sc1);
// channel has only one subchannel right here. // channel has only one subchannel right here.
validate_children(tracer, 1); validate_children(&tracer, 1);
add_simple_trace(sc1); add_simple_trace(&sc1);
grpc_channel_tracer* conn1 = GRPC_CHANNEL_TRACER_CREATE(5); ChannelTracer conn1(5);
// nesting one level deeper. // nesting one level deeper.
grpc_channel_tracer_add_trace( sc1.AddTrace(grpc_slice_from_static_string("connection one created"),
sc1, grpc_slice_from_static_string("connection one created"), GRPC_ERROR_NONE, GRPC_CHANNEL_IDLE, &conn1);
GRPC_ERROR_NONE, GRPC_CHANNEL_IDLE, conn1); validate_children(&sc1, 1);
validate_children(sc1, 1); add_simple_trace(&conn1);
add_simple_trace(conn1); add_simple_trace(&tracer);
add_simple_trace(tracer); add_simple_trace(&tracer);
add_simple_trace(tracer); ChannelTracer sc2(5);
grpc_channel_tracer* sc2 = GRPC_CHANNEL_TRACER_CREATE(5); tracer.AddTrace(grpc_slice_from_static_string("subchannel two created"),
grpc_channel_tracer_add_trace( GRPC_ERROR_NONE, GRPC_CHANNEL_IDLE, &sc2);
tracer, grpc_slice_from_static_string("subchannel two created"), validate_children(&tracer, 2);
GRPC_ERROR_NONE, GRPC_CHANNEL_IDLE, sc2);
validate_children(tracer, 2);
// this trace should not get added to the parents children since it is already // this trace should not get added to the parents children since it is already
// present in the tracer. // present in the tracer.
grpc_channel_tracer_add_trace( tracer.AddTrace(grpc_slice_from_static_string("subchannel one inactive"),
tracer, grpc_slice_from_static_string("subchannel one inactive"), GRPC_ERROR_NONE, GRPC_CHANNEL_IDLE, &sc1);
GRPC_ERROR_NONE, GRPC_CHANNEL_IDLE, sc1); validate_children(&tracer, 2);
validate_children(tracer, 2); add_simple_trace(&tracer);
add_simple_trace(tracer);
conn1.Unref();
GRPC_CHANNEL_TRACER_UNREF(conn1); sc1.Unref();
GRPC_CHANNEL_TRACER_UNREF(sc1); sc2.Unref();
GRPC_CHANNEL_TRACER_UNREF(sc2); tracer.Unref();
GRPC_CHANNEL_TRACER_UNREF(tracer);
} }
int main(int argc, char** argv) { int main(int argc, char** argv) {

Loading…
Cancel
Save