1 /*
2 *
3 * Copyright 2017 gRPC authors.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 */
18
19 #include <grpc/impl/codegen/port_platform.h>
20
21 #include "src/core/lib/channel/channel_trace.h"
22
23 #include <grpc/grpc.h>
24 #include <grpc/support/alloc.h>
25 #include <grpc/support/log.h>
26 #include <grpc/support/string_util.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include "src/core/lib/channel/status_util.h"
32 #include "src/core/lib/gpr/string.h"
33 #include "src/core/lib/gpr/useful.h"
34 #include "src/core/lib/gprpp/memory.h"
35 #include "src/core/lib/iomgr/error.h"
36 #include "src/core/lib/slice/slice_internal.h"
37 #include "src/core/lib/surface/channel.h"
38 #include "src/core/lib/transport/connectivity_state.h"
39 #include "src/core/lib/transport/error_utils.h"
40
41 namespace grpc_core {
42 namespace channelz {
43
TraceEvent(Severity severity,grpc_slice data,RefCountedPtr<BaseNode> referenced_entity)44 ChannelTrace::TraceEvent::TraceEvent(Severity severity, grpc_slice data,
45 RefCountedPtr<BaseNode> referenced_entity)
46 : severity_(severity),
47 data_(data),
48 timestamp_(grpc_millis_to_timespec(grpc_core::ExecCtx::Get()->Now(),
49 GPR_CLOCK_REALTIME)),
50 next_(nullptr),
51 referenced_entity_(std::move(referenced_entity)) {}
52
TraceEvent(Severity severity,grpc_slice data)53 ChannelTrace::TraceEvent::TraceEvent(Severity severity, grpc_slice data)
54 : severity_(severity),
55 data_(data),
56 timestamp_(grpc_millis_to_timespec(grpc_core::ExecCtx::Get()->Now(),
57 GPR_CLOCK_REALTIME)),
58 next_(nullptr) {}
59
~TraceEvent()60 ChannelTrace::TraceEvent::~TraceEvent() { grpc_slice_unref_internal(data_); }
61
ChannelTrace(size_t max_events)62 ChannelTrace::ChannelTrace(size_t max_events)
63 : num_events_logged_(0),
64 list_size_(0),
65 max_list_size_(max_events),
66 head_trace_(nullptr),
67 tail_trace_(nullptr) {
68 if (max_list_size_ == 0) return; // tracing is disabled if max_events == 0
69 gpr_mu_init(&tracer_mu_);
70 time_created_ = grpc_millis_to_timespec(grpc_core::ExecCtx::Get()->Now(),
71 GPR_CLOCK_REALTIME);
72 }
73
~ChannelTrace()74 ChannelTrace::~ChannelTrace() {
75 if (max_list_size_ == 0) return; // tracing is disabled if max_events == 0
76 TraceEvent* it = head_trace_;
77 while (it != nullptr) {
78 TraceEvent* to_free = it;
79 it = it->next();
80 Delete<TraceEvent>(to_free);
81 }
82 gpr_mu_destroy(&tracer_mu_);
83 }
84
AddTraceEventHelper(TraceEvent * new_trace_event)85 void ChannelTrace::AddTraceEventHelper(TraceEvent* new_trace_event) {
86 ++num_events_logged_;
87 // first event case
88 if (head_trace_ == nullptr) {
89 head_trace_ = tail_trace_ = new_trace_event;
90 }
91 // regular event add case
92 else {
93 tail_trace_->set_next(new_trace_event);
94 tail_trace_ = tail_trace_->next();
95 }
96 ++list_size_;
97 // maybe garbage collect the end
98 if (list_size_ > max_list_size_) {
99 TraceEvent* to_free = head_trace_;
100 head_trace_ = head_trace_->next();
101 Delete<TraceEvent>(to_free);
102 --list_size_;
103 }
104 }
105
AddTraceEvent(Severity severity,grpc_slice data)106 void ChannelTrace::AddTraceEvent(Severity severity, grpc_slice data) {
107 if (max_list_size_ == 0) return; // tracing is disabled if max_events == 0
108 AddTraceEventHelper(New<TraceEvent>(severity, data));
109 }
110
AddTraceEventWithReference(Severity severity,grpc_slice data,RefCountedPtr<BaseNode> referenced_entity)111 void ChannelTrace::AddTraceEventWithReference(
112 Severity severity, grpc_slice data,
113 RefCountedPtr<BaseNode> referenced_entity) {
114 if (max_list_size_ == 0) return; // tracing is disabled if max_events == 0
115 // create and fill up the new event
116 AddTraceEventHelper(
117 New<TraceEvent>(severity, data, std::move(referenced_entity)));
118 }
119
120 namespace {
121
severity_string(ChannelTrace::Severity severity)122 const char* severity_string(ChannelTrace::Severity severity) {
123 switch (severity) {
124 case ChannelTrace::Severity::Info:
125 return "CT_INFO";
126 case ChannelTrace::Severity::Warning:
127 return "CT_WARNING";
128 case ChannelTrace::Severity::Error:
129 return "CT_ERROR";
130 default:
131 GPR_UNREACHABLE_CODE(return "CT_UNKNOWN");
132 }
133 }
134
135 } // anonymous namespace
136
RenderTraceEvent(grpc_json * json) const137 void ChannelTrace::TraceEvent::RenderTraceEvent(grpc_json* json) const {
138 grpc_json* json_iterator = nullptr;
139 json_iterator = grpc_json_create_child(json_iterator, json, "description",
140 grpc_slice_to_c_string(data_),
141 GRPC_JSON_STRING, true);
142 json_iterator = grpc_json_create_child(json_iterator, json, "severity",
143 severity_string(severity_),
144 GRPC_JSON_STRING, false);
145 json_iterator = grpc_json_create_child(json_iterator, json, "timestamp",
146 gpr_format_timespec(timestamp_),
147 GRPC_JSON_STRING, true);
148 if (referenced_entity_ != nullptr) {
149 const bool is_channel =
150 (referenced_entity_->type() == BaseNode::EntityType::kTopLevelChannel ||
151 referenced_entity_->type() == BaseNode::EntityType::kInternalChannel);
152 char* uuid_str;
153 gpr_asprintf(&uuid_str, "%" PRIdPTR, referenced_entity_->uuid());
154 grpc_json* child_ref = grpc_json_create_child(
155 json_iterator, json, is_channel ? "channelRef" : "subchannelRef",
156 nullptr, GRPC_JSON_OBJECT, false);
157 json_iterator = grpc_json_create_child(
158 nullptr, child_ref, is_channel ? "channelId" : "subchannelId", uuid_str,
159 GRPC_JSON_STRING, true);
160 json_iterator = child_ref;
161 }
162 }
163
RenderJson() const164 grpc_json* ChannelTrace::RenderJson() const {
165 if (!max_list_size_)
166 return nullptr; // tracing is disabled if max_events == 0
167 grpc_json* json = grpc_json_create(GRPC_JSON_OBJECT);
168 grpc_json* json_iterator = nullptr;
169 if (num_events_logged_ > 0) {
170 json_iterator = grpc_json_add_number_string_child(
171 json, json_iterator, "numEventsLogged", num_events_logged_);
172 }
173 json_iterator = grpc_json_create_child(
174 json_iterator, json, "creationTimestamp",
175 gpr_format_timespec(time_created_), GRPC_JSON_STRING, true);
176 // only add in the event list if it is non-empty.
177 if (num_events_logged_ > 0) {
178 grpc_json* events = grpc_json_create_child(json_iterator, json, "events",
179 nullptr, GRPC_JSON_ARRAY, false);
180 json_iterator = nullptr;
181 TraceEvent* it = head_trace_;
182 while (it != nullptr) {
183 json_iterator = grpc_json_create_child(json_iterator, events, nullptr,
184 nullptr, GRPC_JSON_OBJECT, false);
185 it->RenderTraceEvent(json_iterator);
186 it = it->next();
187 }
188 }
189 return json;
190 }
191
192 } // namespace channelz
193 } // namespace grpc_core
194