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/support/port_platform.h>
20
21 #include "src/core/lib/channel/channel_trace.h"
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include <grpc/grpc.h>
28 #include <grpc/support/alloc.h>
29 #include <grpc/support/log.h>
30 #include <grpc/support/string_util.h>
31
32 #include "src/core/lib/channel/status_util.h"
33 #include "src/core/lib/gpr/string.h"
34 #include "src/core/lib/gpr/useful.h"
35 #include "src/core/lib/gprpp/memory.h"
36 #include "src/core/lib/iomgr/error.h"
37 #include "src/core/lib/slice/slice_internal.h"
38 #include "src/core/lib/surface/channel.h"
39 #include "src/core/lib/transport/connectivity_state.h"
40 #include "src/core/lib/transport/error_utils.h"
41
42 namespace grpc_core {
43 namespace channelz {
44
TraceEvent(Severity severity,const grpc_slice & data,RefCountedPtr<BaseNode> referenced_entity)45 ChannelTrace::TraceEvent::TraceEvent(Severity severity, const grpc_slice& data,
46 RefCountedPtr<BaseNode> referenced_entity)
47 : severity_(severity),
48 data_(data),
49 timestamp_(
50 grpc_millis_to_timespec(ExecCtx::Get()->Now(), GPR_CLOCK_REALTIME)),
51 next_(nullptr),
52 referenced_entity_(std::move(referenced_entity)),
53 memory_usage_(sizeof(TraceEvent) + grpc_slice_memory_usage(data)) {}
54
TraceEvent(Severity severity,const grpc_slice & data)55 ChannelTrace::TraceEvent::TraceEvent(Severity severity, const grpc_slice& data)
56 : severity_(severity),
57 data_(data),
58 timestamp_(
59 grpc_millis_to_timespec(ExecCtx::Get()->Now(), GPR_CLOCK_REALTIME)),
60 next_(nullptr),
61 memory_usage_(sizeof(TraceEvent) + grpc_slice_memory_usage(data)) {}
62
~TraceEvent()63 ChannelTrace::TraceEvent::~TraceEvent() { grpc_slice_unref_internal(data_); }
64
ChannelTrace(size_t max_event_memory)65 ChannelTrace::ChannelTrace(size_t max_event_memory)
66 : num_events_logged_(0),
67 event_list_memory_usage_(0),
68 max_event_memory_(max_event_memory),
69 head_trace_(nullptr),
70 tail_trace_(nullptr) {
71 if (max_event_memory_ == 0) {
72 return; // tracing is disabled if max_event_memory_ == 0
73 }
74 gpr_mu_init(&tracer_mu_);
75 time_created_ =
76 grpc_millis_to_timespec(ExecCtx::Get()->Now(), GPR_CLOCK_REALTIME);
77 }
78
~ChannelTrace()79 ChannelTrace::~ChannelTrace() {
80 if (max_event_memory_ == 0) {
81 return; // tracing is disabled if max_event_memory_ == 0
82 }
83 TraceEvent* it = head_trace_;
84 while (it != nullptr) {
85 TraceEvent* to_free = it;
86 it = it->next();
87 delete to_free;
88 }
89 gpr_mu_destroy(&tracer_mu_);
90 }
91
AddTraceEventHelper(TraceEvent * new_trace_event)92 void ChannelTrace::AddTraceEventHelper(TraceEvent* new_trace_event) {
93 ++num_events_logged_;
94 // first event case
95 if (head_trace_ == nullptr) {
96 head_trace_ = tail_trace_ = new_trace_event;
97 }
98 // regular event add case
99 else {
100 tail_trace_->set_next(new_trace_event);
101 tail_trace_ = tail_trace_->next();
102 }
103 event_list_memory_usage_ += new_trace_event->memory_usage();
104 // maybe garbage collect the tail until we are under the memory limit.
105 while (event_list_memory_usage_ > max_event_memory_) {
106 TraceEvent* to_free = head_trace_;
107 event_list_memory_usage_ -= to_free->memory_usage();
108 head_trace_ = head_trace_->next();
109 delete to_free;
110 }
111 }
112
AddTraceEvent(Severity severity,const grpc_slice & data)113 void ChannelTrace::AddTraceEvent(Severity severity, const grpc_slice& data) {
114 if (max_event_memory_ == 0) {
115 grpc_slice_unref_internal(data);
116 return; // tracing is disabled if max_event_memory_ == 0
117 }
118 AddTraceEventHelper(new TraceEvent(severity, data));
119 }
120
AddTraceEventWithReference(Severity severity,const grpc_slice & data,RefCountedPtr<BaseNode> referenced_entity)121 void ChannelTrace::AddTraceEventWithReference(
122 Severity severity, const grpc_slice& data,
123 RefCountedPtr<BaseNode> referenced_entity) {
124 if (max_event_memory_ == 0) {
125 grpc_slice_unref_internal(data);
126 return; // tracing is disabled if max_event_memory_ == 0
127 }
128 // create and fill up the new event
129 AddTraceEventHelper(
130 new TraceEvent(severity, data, std::move(referenced_entity)));
131 }
132
133 namespace {
134
severity_string(ChannelTrace::Severity severity)135 const char* severity_string(ChannelTrace::Severity severity) {
136 switch (severity) {
137 case ChannelTrace::Severity::Info:
138 return "CT_INFO";
139 case ChannelTrace::Severity::Warning:
140 return "CT_WARNING";
141 case ChannelTrace::Severity::Error:
142 return "CT_ERROR";
143 default:
144 GPR_UNREACHABLE_CODE(return "CT_UNKNOWN");
145 }
146 }
147
148 } // anonymous namespace
149
RenderTraceEvent() const150 Json ChannelTrace::TraceEvent::RenderTraceEvent() const {
151 char* description = grpc_slice_to_c_string(data_);
152 Json::Object object = {
153 {"description", description},
154 {"severity", severity_string(severity_)},
155 {"timestamp", gpr_format_timespec(timestamp_)},
156 };
157 gpr_free(description);
158 if (referenced_entity_ != nullptr) {
159 const bool is_channel =
160 (referenced_entity_->type() == BaseNode::EntityType::kTopLevelChannel ||
161 referenced_entity_->type() == BaseNode::EntityType::kInternalChannel);
162 object[is_channel ? "channelRef" : "subchannelRef"] = Json::Object{
163 {(is_channel ? "channelId" : "subchannelId"),
164 std::to_string(referenced_entity_->uuid())},
165 };
166 }
167 return object;
168 }
169
RenderJson() const170 Json ChannelTrace::RenderJson() const {
171 // Tracing is disabled if max_event_memory_ == 0.
172 if (max_event_memory_ == 0) {
173 return Json(); // JSON null
174 }
175 Json::Object object = {
176 {"creationTimestamp", gpr_format_timespec(time_created_)},
177 };
178 if (num_events_logged_ > 0) {
179 object["numEventsLogged"] = std::to_string(num_events_logged_);
180 }
181 // Only add in the event list if it is non-empty.
182 if (head_trace_ != nullptr) {
183 Json::Array array;
184 for (TraceEvent* it = head_trace_; it != nullptr; it = it->next()) {
185 array.emplace_back(it->RenderTraceEvent());
186 }
187 object["events"] = std::move(array);
188 }
189 return object;
190 }
191
192 } // namespace channelz
193 } // namespace grpc_core
194