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