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