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