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