xref: /aosp_15_r20/external/grpc-grpc/test/core/channel/channel_trace_test.cc (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
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/lib/channel/channel_trace.h"
20 
21 #include <stdlib.h>
22 
23 #include <string>
24 
25 #include "gtest/gtest.h"
26 
27 #include <grpc/grpc.h>
28 #include <grpc/grpc_security.h>
29 #include <grpc/impl/channel_arg_names.h>
30 
31 #include "src/core/lib/channel/channel_args.h"
32 #include "src/core/lib/channel/channelz.h"
33 #include "src/core/lib/iomgr/exec_ctx.h"
34 #include "src/core/lib/json/json.h"
35 #include "src/core/lib/json/json_writer.h"
36 #include "test/core/util/test_config.h"
37 #include "test/cpp/util/channel_trace_proto_helper.h"
38 
39 namespace grpc_core {
40 namespace channelz {
41 namespace testing {
42 
43 // testing peer to access channel internals
44 class ChannelNodePeer {
45  public:
ChannelNodePeer(ChannelNode * node)46   explicit ChannelNodePeer(ChannelNode* node) : node_(node) {}
trace() const47   ChannelTrace* trace() const { return &node_->trace_; }
48 
49  private:
50   ChannelNode* node_;
51 };
52 
GetSizeofTraceEvent()53 size_t GetSizeofTraceEvent() { return sizeof(ChannelTrace::TraceEvent); }
54 
55 namespace {
56 
ValidateJsonArraySize(const Json & array,size_t expected)57 void ValidateJsonArraySize(const Json& array, size_t expected) {
58   if (expected == 0) {
59     ASSERT_EQ(array.type(), Json::Type::kNull);
60   } else {
61     ASSERT_EQ(array.type(), Json::Type::kArray);
62     EXPECT_EQ(array.array().size(), expected);
63   }
64 }
65 
ValidateChannelTraceData(const Json & json,size_t num_events_logged_expected,size_t actual_num_events_expected)66 void ValidateChannelTraceData(const Json& json,
67                               size_t num_events_logged_expected,
68                               size_t actual_num_events_expected) {
69   ASSERT_EQ(json.type(), Json::Type::kObject);
70   Json::Object object = json.object();
71   Json& num_events_logged_json = object["numEventsLogged"];
72   ASSERT_EQ(num_events_logged_json.type(), Json::Type::kString);
73   size_t num_events_logged = static_cast<size_t>(
74       strtol(num_events_logged_json.string().c_str(), nullptr, 0));
75   ASSERT_EQ(num_events_logged, num_events_logged_expected);
76   Json& start_time_json = object["creationTimestamp"];
77   ASSERT_EQ(start_time_json.type(), Json::Type::kString);
78   ValidateJsonArraySize(object["events"], actual_num_events_expected);
79 }
80 
AddSimpleTrace(ChannelTrace * tracer)81 void AddSimpleTrace(ChannelTrace* tracer) {
82   tracer->AddTraceEvent(ChannelTrace::Severity::Info,
83                         grpc_slice_from_static_string("simple trace"));
84 }
85 
86 // checks for the existence of all the required members of the tracer.
ValidateChannelTraceCustom(ChannelTrace * tracer,size_t num_events_logged,size_t num_events_expected)87 void ValidateChannelTraceCustom(ChannelTrace* tracer, size_t num_events_logged,
88                                 size_t num_events_expected) {
89   Json json = tracer->RenderJson();
90   ASSERT_EQ(json.type(), Json::Type::kObject);
91   std::string json_str = JsonDump(json);
92   grpc::testing::ValidateChannelTraceProtoJsonTranslation(json_str.c_str());
93   ValidateChannelTraceData(json, num_events_logged, num_events_expected);
94 }
95 
ValidateChannelTrace(ChannelTrace * tracer,size_t num_events_logged)96 void ValidateChannelTrace(ChannelTrace* tracer, size_t num_events_logged) {
97   ValidateChannelTraceCustom(tracer, num_events_logged, num_events_logged);
98 }
99 
100 class ChannelFixture {
101  public:
ChannelFixture(int max_tracer_event_memory)102   explicit ChannelFixture(int max_tracer_event_memory) {
103     grpc_arg client_a = grpc_channel_arg_integer_create(
104         const_cast<char*>(GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE),
105         max_tracer_event_memory);
106     grpc_channel_args client_args = {1, &client_a};
107     grpc_channel_credentials* creds = grpc_insecure_credentials_create();
108     channel_ = grpc_channel_create("fake_target", creds, &client_args);
109     grpc_channel_credentials_release(creds);
110   }
111 
~ChannelFixture()112   ~ChannelFixture() { grpc_channel_destroy(channel_); }
113 
channel()114   grpc_channel* channel() { return channel_; }
115 
116  private:
117   grpc_channel* channel_;
118 };
119 
120 }  // anonymous namespace
121 
122 const int kEventListMemoryLimit = 1024 * 1024;
123 
124 // Tests basic ChannelTrace functionality like construction, adding trace, and
125 // lookups by uuid.
TEST(ChannelTracerTest,BasicTest)126 TEST(ChannelTracerTest, BasicTest) {
127   ExecCtx exec_ctx;
128   ChannelTrace tracer(kEventListMemoryLimit);
129   AddSimpleTrace(&tracer);
130   AddSimpleTrace(&tracer);
131   tracer.AddTraceEvent(ChannelTrace::Severity::Info,
132                        grpc_slice_from_static_string("trace three"));
133   tracer.AddTraceEvent(ChannelTrace::Severity::Error,
134                        grpc_slice_from_static_string("trace four error"));
135   ValidateChannelTrace(&tracer, 4);
136   AddSimpleTrace(&tracer);
137   AddSimpleTrace(&tracer);
138   ValidateChannelTrace(&tracer, 6);
139   AddSimpleTrace(&tracer);
140   AddSimpleTrace(&tracer);
141   AddSimpleTrace(&tracer);
142   AddSimpleTrace(&tracer);
143   ValidateChannelTrace(&tracer, 10);
144 }
145 
146 // Tests more complex functionality, like a parent channel tracking
147 // subchannles. This exercises the ref/unref patterns since the parent tracer
148 // and this function will both hold refs to the subchannel.
TEST(ChannelTracerTest,ComplexTest)149 TEST(ChannelTracerTest, ComplexTest) {
150   ExecCtx exec_ctx;
151   ChannelTrace tracer(kEventListMemoryLimit);
152   AddSimpleTrace(&tracer);
153   AddSimpleTrace(&tracer);
154   ChannelFixture channel1(kEventListMemoryLimit);
155   RefCountedPtr<ChannelNode> sc1 =
156       MakeRefCounted<ChannelNode>("fake_target", kEventListMemoryLimit, 0);
157   ChannelNodePeer sc1_peer(sc1.get());
158   tracer.AddTraceEventWithReference(
159       ChannelTrace::Severity::Info,
160       grpc_slice_from_static_string("subchannel one created"), sc1);
161   ValidateChannelTrace(&tracer, 3);
162   AddSimpleTrace(sc1_peer.trace());
163   AddSimpleTrace(sc1_peer.trace());
164   AddSimpleTrace(sc1_peer.trace());
165   ValidateChannelTrace(sc1_peer.trace(), 3);
166   AddSimpleTrace(sc1_peer.trace());
167   AddSimpleTrace(sc1_peer.trace());
168   AddSimpleTrace(sc1_peer.trace());
169   ValidateChannelTrace(sc1_peer.trace(), 6);
170   AddSimpleTrace(&tracer);
171   AddSimpleTrace(&tracer);
172   ValidateChannelTrace(&tracer, 5);
173   ChannelFixture channel2(kEventListMemoryLimit);
174   RefCountedPtr<ChannelNode> sc2 =
175       MakeRefCounted<ChannelNode>("fake_target", kEventListMemoryLimit, 0);
176   tracer.AddTraceEventWithReference(
177       ChannelTrace::Severity::Info,
178       grpc_slice_from_static_string("LB channel two created"), sc2);
179   tracer.AddTraceEventWithReference(
180       ChannelTrace::Severity::Warning,
181       grpc_slice_from_static_string("subchannel one inactive"), sc1);
182   ValidateChannelTrace(&tracer, 7);
183   AddSimpleTrace(&tracer);
184   AddSimpleTrace(&tracer);
185   AddSimpleTrace(&tracer);
186   AddSimpleTrace(&tracer);
187   AddSimpleTrace(&tracer);
188   AddSimpleTrace(&tracer);
189   sc1.reset();
190   sc2.reset();
191 }
192 
193 // Test a case in which the parent channel has subchannels and the subchannels
194 // have connections. Ensures that everything lives as long as it should then
195 // gets deleted.
TEST(ChannelTracerTest,TestNesting)196 TEST(ChannelTracerTest, TestNesting) {
197   ExecCtx exec_ctx;
198   ChannelTrace tracer(kEventListMemoryLimit);
199   AddSimpleTrace(&tracer);
200   AddSimpleTrace(&tracer);
201   ValidateChannelTrace(&tracer, 2);
202   ChannelFixture channel1(kEventListMemoryLimit);
203   RefCountedPtr<ChannelNode> sc1 =
204       MakeRefCounted<ChannelNode>("fake_target", kEventListMemoryLimit, 0);
205   ChannelNodePeer sc1_peer(sc1.get());
206   tracer.AddTraceEventWithReference(
207       ChannelTrace::Severity::Info,
208       grpc_slice_from_static_string("subchannel one created"), sc1);
209   ValidateChannelTrace(&tracer, 3);
210   AddSimpleTrace(sc1_peer.trace());
211   ChannelFixture channel2(kEventListMemoryLimit);
212   RefCountedPtr<ChannelNode> conn1 =
213       MakeRefCounted<ChannelNode>("fake_target", kEventListMemoryLimit, 0);
214   ChannelNodePeer conn1_peer(conn1.get());
215   // nesting one level deeper.
216   sc1_peer.trace()->AddTraceEventWithReference(
217       ChannelTrace::Severity::Info,
218       grpc_slice_from_static_string("connection one created"), conn1);
219   ValidateChannelTrace(&tracer, 3);
220   AddSimpleTrace(conn1_peer.trace());
221   AddSimpleTrace(&tracer);
222   AddSimpleTrace(&tracer);
223   ValidateChannelTrace(&tracer, 5);
224   ValidateChannelTrace(conn1_peer.trace(), 1);
225   ChannelFixture channel3(kEventListMemoryLimit);
226   RefCountedPtr<ChannelNode> sc2 =
227       MakeRefCounted<ChannelNode>("fake_target", kEventListMemoryLimit, 0);
228   tracer.AddTraceEventWithReference(
229       ChannelTrace::Severity::Info,
230       grpc_slice_from_static_string("subchannel two created"), sc2);
231   // this trace should not get added to the parents children since it is already
232   // present in the tracer.
233   tracer.AddTraceEventWithReference(
234       ChannelTrace::Severity::Warning,
235       grpc_slice_from_static_string("subchannel one inactive"), sc1);
236   AddSimpleTrace(&tracer);
237   ValidateChannelTrace(&tracer, 8);
238   sc1.reset();
239   sc2.reset();
240   conn1.reset();
241 }
242 
TEST(ChannelTracerTest,TestSmallMemoryLimit)243 TEST(ChannelTracerTest, TestSmallMemoryLimit) {
244   ExecCtx exec_ctx;
245   // doesn't make sense, but serves a testing purpose for the channel tracing
246   // bookkeeping. All tracing events added should will get immediately garbage
247   // collected.
248   const int kSmallMemoryLimit = 1;
249   ChannelTrace tracer(kSmallMemoryLimit);
250   AddSimpleTrace(&tracer);
251   AddSimpleTrace(&tracer);
252   tracer.AddTraceEvent(ChannelTrace::Severity::Info,
253                        grpc_slice_from_static_string("trace three"));
254   tracer.AddTraceEvent(ChannelTrace::Severity::Error,
255                        grpc_slice_from_static_string("trace four error"));
256   ValidateChannelTraceCustom(&tracer, 4, 0);
257   AddSimpleTrace(&tracer);
258   AddSimpleTrace(&tracer);
259   ValidateChannelTraceCustom(&tracer, 6, 0);
260   AddSimpleTrace(&tracer);
261   AddSimpleTrace(&tracer);
262   AddSimpleTrace(&tracer);
263   AddSimpleTrace(&tracer);
264   ValidateChannelTraceCustom(&tracer, 10, 0);
265 }
266 
TEST(ChannelTracerTest,TestEviction)267 TEST(ChannelTracerTest, TestEviction) {
268   ExecCtx exec_ctx;
269   const int kTraceEventSize = GetSizeofTraceEvent();
270   const int kNumEvents = 5;
271   ChannelTrace tracer(kTraceEventSize * kNumEvents);
272   for (int i = 1; i <= kNumEvents; ++i) {
273     AddSimpleTrace(&tracer);
274     ValidateChannelTrace(&tracer, i);
275   }
276   // at this point the list is full, and each subsequent enntry will cause an
277   // eviction.
278   for (int i = 1; i <= kNumEvents; ++i) {
279     AddSimpleTrace(&tracer);
280     ValidateChannelTraceCustom(&tracer, kNumEvents + i, kNumEvents);
281   }
282 }
283 
TEST(ChannelTracerTest,TestMultipleEviction)284 TEST(ChannelTracerTest, TestMultipleEviction) {
285   ExecCtx exec_ctx;
286   const int kTraceEventSize = GetSizeofTraceEvent();
287   const int kNumEvents = 5;
288   ChannelTrace tracer(kTraceEventSize * kNumEvents);
289   for (int i = 1; i <= kNumEvents; ++i) {
290     AddSimpleTrace(&tracer);
291     ValidateChannelTrace(&tracer, i);
292   }
293   // at this point the list is full, and each subsequent enntry will cause an
294   // eviction. We will now add in a trace event that has a copied string. This
295   // uses more memory, so it will cause a double eviciction
296   tracer.AddTraceEvent(
297       ChannelTrace::Severity::Info,
298       grpc_slice_from_copied_string(
299           "long enough string to trigger a multiple eviction"));
300   ValidateChannelTraceCustom(&tracer, kNumEvents + 1, kNumEvents - 1);
301 }
302 
TEST(ChannelTracerTest,TestTotalEviction)303 TEST(ChannelTracerTest, TestTotalEviction) {
304   ExecCtx exec_ctx;
305   const int kTraceEventSize = GetSizeofTraceEvent();
306   const int kNumEvents = 5;
307   ChannelTrace tracer(kTraceEventSize * kNumEvents);
308   for (int i = 1; i <= kNumEvents; ++i) {
309     AddSimpleTrace(&tracer);
310     ValidateChannelTrace(&tracer, i);
311   }
312   // at this point the list is full. Now we add such a big slice that
313   // everything gets evicted.
314   grpc_slice huge_slice = grpc_slice_malloc(kTraceEventSize * (kNumEvents + 1));
315   tracer.AddTraceEvent(ChannelTrace::Severity::Info, huge_slice);
316   ValidateChannelTraceCustom(&tracer, kNumEvents + 1, 0);
317 }
318 
319 }  // namespace testing
320 }  // namespace channelz
321 }  // namespace grpc_core
322 
main(int argc,char ** argv)323 int main(int argc, char** argv) {
324   grpc::testing::TestEnvironment env(&argc, argv);
325   grpc_init();
326   ::testing::InitGoogleTest(&argc, argv);
327   int ret = RUN_ALL_TESTS();
328   grpc_shutdown();
329   return ret;
330 }
331