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