• 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/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