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