• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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