1 //
2 // Copyright 2022 gRPC authors.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 #include "src/cpp/ext/gcp/observability_logging_sink.h"
18
19 #include "absl/strings/escaping.h"
20 #include "absl/strings/str_format.h"
21 #include "gmock/gmock.h"
22 #include "google/protobuf/text_format.h"
23 #include "gtest/gtest.h"
24
25 #include "src/core/lib/json/json_reader.h"
26 #include "test/core/util/test_config.h"
27
28 namespace grpc {
29 namespace internal {
30
31 namespace {
32
33 using grpc_core::LoggingSink;
34
TEST(GcpObservabilityLoggingSinkTest,LoggingConfigEmpty)35 TEST(GcpObservabilityLoggingSinkTest, LoggingConfigEmpty) {
36 const char* json_str = R"json({
37 "cloud_logging": {
38 }
39 })json";
40 auto json = grpc_core::JsonParse(json_str);
41 ASSERT_TRUE(json.ok()) << json.status();
42 grpc_core::ValidationErrors errors;
43 auto config = grpc_core::LoadFromJson<GcpObservabilityConfig>(
44 *json, grpc_core::JsonArgs(), &errors);
45 ASSERT_TRUE(errors.ok()) << errors.status(absl::StatusCode::kInvalidArgument,
46 "unexpected errors");
47 ObservabilityLoggingSink sink(config.cloud_logging.value(), "test", {});
48 // client test
49 EXPECT_FALSE(sink.FindMatch(true, "foo", "bar").ShouldLog());
50 // server test
51 EXPECT_FALSE(sink.FindMatch(false, "foo", "bar").ShouldLog());
52 }
53
TEST(GcpObservabilityLoggingSinkTest,LoggingConfigClientWildCardEntries)54 TEST(GcpObservabilityLoggingSinkTest, LoggingConfigClientWildCardEntries) {
55 const char* json_str = R"json({
56 "cloud_logging": {
57 "client_rpc_events": [
58 {
59 "methods": ["*"],
60 "max_metadata_bytes": 1024,
61 "max_message_bytes": 4096
62 }
63 ]
64 }
65 })json";
66 auto json = grpc_core::JsonParse(json_str);
67 ASSERT_TRUE(json.ok()) << json.status();
68 grpc_core::ValidationErrors errors;
69 auto config = grpc_core::LoadFromJson<GcpObservabilityConfig>(
70 *json, grpc_core::JsonArgs(), &errors);
71 ASSERT_TRUE(errors.ok()) << errors.status(absl::StatusCode::kInvalidArgument,
72 "unexpected errors");
73 ObservabilityLoggingSink sink(config.cloud_logging.value(), "test", {});
74 // client test
75 EXPECT_EQ(sink.FindMatch(true, "foo", "bar"),
76 LoggingSink::Config(1024, 4096));
77 // server test
78 EXPECT_FALSE(sink.FindMatch(false, "foo", "bar").ShouldLog());
79 }
80
TEST(GcpObservabilityLoggingSinkTest,LoggingConfigBadPath)81 TEST(GcpObservabilityLoggingSinkTest, LoggingConfigBadPath) {
82 const char* json_str = R"json({
83 "cloud_logging": {
84 "client_rpc_events": [
85 {
86 "methods": ["*"],
87 "max_metadata_bytes": 1024,
88 "max_message_bytes": 4096
89 }
90 ]
91 }
92 })json";
93 auto json = grpc_core::JsonParse(json_str);
94 ASSERT_TRUE(json.ok()) << json.status();
95 grpc_core::ValidationErrors errors;
96 auto config = grpc_core::LoadFromJson<GcpObservabilityConfig>(
97 *json, grpc_core::JsonArgs(), &errors);
98 ASSERT_TRUE(errors.ok()) << errors.status(absl::StatusCode::kInvalidArgument,
99 "unexpected errors");
100 ObservabilityLoggingSink sink(config.cloud_logging.value(), "test", {});
101 EXPECT_FALSE(sink.FindMatch(true, "foo", "").ShouldLog());
102 }
103
TEST(GcpObservabilityLoggingSinkTest,LoggingConfigClientWildCardServiceEntries)104 TEST(GcpObservabilityLoggingSinkTest,
105 LoggingConfigClientWildCardServiceEntries) {
106 const char* json_str = R"json({
107 "cloud_logging": {
108 "client_rpc_events": [
109 {
110 "methods": ["service/*"],
111 "max_metadata_bytes": 1024,
112 "max_message_bytes": 4096
113 }
114 ]
115 }
116 })json";
117 auto json = grpc_core::JsonParse(json_str);
118 ASSERT_TRUE(json.ok()) << json.status();
119 grpc_core::ValidationErrors errors;
120 auto config = grpc_core::LoadFromJson<GcpObservabilityConfig>(
121 *json, grpc_core::JsonArgs(), &errors);
122 ASSERT_TRUE(errors.ok()) << errors.status(absl::StatusCode::kInvalidArgument,
123 "unexpected errors");
124 ObservabilityLoggingSink sink(config.cloud_logging.value(), "test", {});
125 // client test
126 EXPECT_EQ(sink.FindMatch(true, "service", "bar"),
127 LoggingSink::Config(1024, 4096));
128 EXPECT_FALSE(sink.FindMatch(true, "foo", "bar").ShouldLog());
129 // server test
130 EXPECT_FALSE(sink.FindMatch(false, "service", "bar").ShouldLog());
131 EXPECT_FALSE(sink.FindMatch(false, "foo", "bar").ShouldLog());
132 }
133
134 TEST(GcpObservabilityLoggingSinkTest,
135 LoggingConfigClientMultipleMethodEntries) {
136 const char* json_str = R"json({
137 "cloud_logging": {
138 "client_rpc_events": [
139 {
140 "methods": ["foo/bar", "foo/baz"],
141 "max_metadata_bytes": 1024,
142 "max_message_bytes": 4096
143 }
144 ]
145 }
146 })json";
147 auto json = grpc_core::JsonParse(json_str);
148 ASSERT_TRUE(json.ok()) << json.status();
149 grpc_core::ValidationErrors errors;
150 auto config = grpc_core::LoadFromJson<GcpObservabilityConfig>(
151 *json, grpc_core::JsonArgs(), &errors);
152 ASSERT_TRUE(errors.ok()) << errors.status(absl::StatusCode::kInvalidArgument,
153 "unexpected errors");
154 ObservabilityLoggingSink sink(config.cloud_logging.value(), "test", {});
155 // client test
156 EXPECT_EQ(sink.FindMatch(true, "foo", "bar"),
157 LoggingSink::Config(1024, 4096));
158 EXPECT_EQ(sink.FindMatch(true, "foo", "baz"),
159 LoggingSink::Config(1024, 4096));
160 // server test
161 EXPECT_FALSE(sink.FindMatch(false, "foo", "bar").ShouldLog());
162 EXPECT_FALSE(sink.FindMatch(false, "foo", "baz").ShouldLog());
163 }
164
165 TEST(GcpObservabilityLoggingSinkTest, LoggingConfigClientMultipleEventEntries) {
166 const char* json_str = R"json({
167 "cloud_logging": {
168 "client_rpc_events": [
169 {
170 "methods": ["foo/bar"],
171 "max_metadata_bytes": 1024,
172 "max_message_bytes": 4096
173 },
174 {
175 "methods": ["foo/baz"],
176 "max_metadata_bytes": 512,
177 "max_message_bytes": 2048
178 }
179 ]
180 }
181 })json";
182 auto json = grpc_core::JsonParse(json_str);
183 ASSERT_TRUE(json.ok()) << json.status();
184 grpc_core::ValidationErrors errors;
185 auto config = grpc_core::LoadFromJson<GcpObservabilityConfig>(
186 *json, grpc_core::JsonArgs(), &errors);
187 ASSERT_TRUE(errors.ok()) << errors.status(absl::StatusCode::kInvalidArgument,
188 "unexpected errors");
189 ObservabilityLoggingSink sink(config.cloud_logging.value(), "test", {});
190 // client test
191 EXPECT_EQ(sink.FindMatch(true, "foo", "bar"),
192 LoggingSink::Config(1024, 4096));
193 EXPECT_EQ(sink.FindMatch(true, "foo", "baz"), LoggingSink::Config(512, 2048));
194 // server test
195 EXPECT_FALSE(sink.FindMatch(false, "foo", "bar").ShouldLog());
196 EXPECT_FALSE(sink.FindMatch(false, "foo", "baz").ShouldLog());
197 }
198
199 TEST(GcpObservabilityLoggingSinkTest, LoggingConfigServerWildCardEntries) {
200 const char* json_str = R"json({
201 "cloud_logging": {
202 "server_rpc_events": [
203 {
204 "methods": ["*"],
205 "max_metadata_bytes": 1024,
206 "max_message_bytes": 4096
207 }
208 ]
209 }
210 })json";
211 auto json = grpc_core::JsonParse(json_str);
212 ASSERT_TRUE(json.ok()) << json.status();
213 grpc_core::ValidationErrors errors;
214 auto config = grpc_core::LoadFromJson<GcpObservabilityConfig>(
215 *json, grpc_core::JsonArgs(), &errors);
216 ASSERT_TRUE(errors.ok()) << errors.status(absl::StatusCode::kInvalidArgument,
217 "unexpected errors");
218 ObservabilityLoggingSink sink(config.cloud_logging.value(), "test", {});
219 // client test
220 EXPECT_FALSE(sink.FindMatch(true, "foo", "bar").ShouldLog());
221 // server test
222 EXPECT_EQ(sink.FindMatch(false, "foo", "bar"),
223 LoggingSink::Config(1024, 4096));
224 }
225
226 TEST(GcpObservabilityLoggingSinkTest,
227 LoggingConfigServerWildCardServiceEntries) {
228 const char* json_str = R"json({
229 "cloud_logging": {
230 "server_rpc_events": [
231 {
232 "methods": ["service/*"],
233 "max_metadata_bytes": 1024,
234 "max_message_bytes": 4096
235 }
236 ]
237 }
238 })json";
239 auto json = grpc_core::JsonParse(json_str);
240 ASSERT_TRUE(json.ok()) << json.status();
241 grpc_core::ValidationErrors errors;
242 auto config = grpc_core::LoadFromJson<GcpObservabilityConfig>(
243 *json, grpc_core::JsonArgs(), &errors);
244 ASSERT_TRUE(errors.ok()) << errors.status(absl::StatusCode::kInvalidArgument,
245 "unexpected errors");
246 ObservabilityLoggingSink sink(config.cloud_logging.value(), "test", {});
247 // client test
248 EXPECT_FALSE(sink.FindMatch(true, "service", "bar").ShouldLog());
249 EXPECT_FALSE(sink.FindMatch(true, "foo", "bar").ShouldLog());
250 // server test
251 EXPECT_EQ(sink.FindMatch(false, "service", "bar"),
252 LoggingSink::Config(1024, 4096));
253 EXPECT_FALSE(sink.FindMatch(false, "foo", "bar").ShouldLog());
254 }
255
256 TEST(GcpObservabilityLoggingSinkTest,
257 LoggingConfigServerMultipleMethodEntries) {
258 const char* json_str = R"json({
259 "cloud_logging": {
260 "server_rpc_events": [
261 {
262 "methods": ["foo/bar", "foo/baz"],
263 "max_metadata_bytes": 1024,
264 "max_message_bytes": 4096
265 }
266 ]
267 }
268 })json";
269 auto json = grpc_core::JsonParse(json_str);
270 ASSERT_TRUE(json.ok()) << json.status();
271 grpc_core::ValidationErrors errors;
272 auto config = grpc_core::LoadFromJson<GcpObservabilityConfig>(
273 *json, grpc_core::JsonArgs(), &errors);
274 ASSERT_TRUE(errors.ok()) << errors.status(absl::StatusCode::kInvalidArgument,
275 "unexpected errors");
276 ObservabilityLoggingSink sink(config.cloud_logging.value(), "test", {});
277 // client test
278 EXPECT_FALSE(sink.FindMatch(true, "foo", "bar").ShouldLog());
279 EXPECT_FALSE(sink.FindMatch(true, "foo", "baz").ShouldLog());
280 // server test
281 EXPECT_EQ(sink.FindMatch(false, "foo", "bar"),
282 LoggingSink::Config(1024, 4096));
283 EXPECT_EQ(sink.FindMatch(false, "foo", "baz"),
284 LoggingSink::Config(1024, 4096));
285 }
286
287 TEST(GcpObservabilityLoggingSinkTest, LoggingConfigServerMultipleEventEntries) {
288 const char* json_str = R"json({
289 "cloud_logging": {
290 "server_rpc_events": [
291 {
292 "methods": ["foo/bar"],
293 "max_metadata_bytes": 1024,
294 "max_message_bytes": 4096
295 },
296 {
297 "methods": ["foo/baz"],
298 "max_metadata_bytes": 512,
299 "max_message_bytes": 2048
300 }
301 ]
302 }
303 })json";
304 auto json = grpc_core::JsonParse(json_str);
305 ASSERT_TRUE(json.ok()) << json.status();
306 grpc_core::ValidationErrors errors;
307 auto config = grpc_core::LoadFromJson<GcpObservabilityConfig>(
308 *json, grpc_core::JsonArgs(), &errors);
309 ASSERT_TRUE(errors.ok()) << errors.status(absl::StatusCode::kInvalidArgument,
310 "unexpected errors");
311 ObservabilityLoggingSink sink(config.cloud_logging.value(), "test", {});
312 // client test
313 EXPECT_FALSE(sink.FindMatch(true, "foo", "bar").ShouldLog());
314 EXPECT_FALSE(sink.FindMatch(true, "foo", "baz").ShouldLog());
315 // server test
316 EXPECT_EQ(sink.FindMatch(false, "foo", "bar"),
317 LoggingSink::Config(1024, 4096));
318 EXPECT_EQ(sink.FindMatch(false, "foo", "baz"),
319 LoggingSink::Config(512, 2048));
320 }
321
322 TEST(EntryToJsonStructTest, ClientHeader) {
323 LoggingSink::Entry entry;
324 entry.call_id = 1234;
325 entry.sequence_id = 1;
326 entry.type = LoggingSink::Entry::EventType::kClientHeader;
327 entry.payload.metadata["key"] = "value";
328 entry.payload.timeout = grpc_core::Duration::Seconds(100);
329 entry.payload_truncated = true;
330 entry.peer.type = LoggingSink::Entry::Address::Type::kIpv4;
331 entry.peer.address = "127.0.0.1";
332 entry.peer.ip_port = 12345;
333 entry.authority = "authority";
334 entry.service_name = "service_name";
335 entry.method_name = "method_name";
336
337 google::protobuf::Struct proto;
338 EntryToJsonStructProto(std::move(entry), &proto);
339 std::string output;
340 ::google::protobuf::TextFormat::PrintToString(proto, &output);
341 const char* pb_str =
342 "fields {\n"
343 " key: \"authority\"\n"
344 " value {\n"
345 " string_value: \"authority\"\n"
346 " }\n"
347 "}\n"
348 "fields {\n"
349 " key: \"callId\"\n"
350 " value {\n"
351 " string_value: \"00000000-0000-4000-8000-0000000004d2\"\n"
352 " }\n"
353 "}\n"
354 "fields {\n"
355 " key: \"logger\"\n"
356 " value {\n"
357 " string_value: \"LOGGER_UNKNOWN\"\n"
358 " }\n"
359 "}\n"
360 "fields {\n"
361 " key: \"methodName\"\n"
362 " value {\n"
363 " string_value: \"method_name\"\n"
364 " }\n"
365 "}\n"
366 "fields {\n"
367 " key: \"payload\"\n"
368 " value {\n"
369 " struct_value {\n"
370 " fields {\n"
371 " key: \"metadata\"\n"
372 " value {\n"
373 " struct_value {\n"
374 " fields {\n"
375 " key: \"key\"\n"
376 " value {\n"
377 " string_value: \"value\"\n"
378 " }\n"
379 " }\n"
380 " }\n"
381 " }\n"
382 " }\n"
383 " fields {\n"
384 " key: \"timeout\"\n"
385 " value {\n"
386 " string_value: \"100.000000000s\"\n"
387 " }\n"
388 " }\n"
389 " }\n"
390 " }\n"
391 "}\n"
392 "fields {\n"
393 " key: \"payloadTruncated\"\n"
394 " value {\n"
395 " bool_value: true\n"
396 " }\n"
397 "}\n"
398 "fields {\n"
399 " key: \"peer\"\n"
400 " value {\n"
401 " struct_value {\n"
402 " fields {\n"
403 " key: \"address\"\n"
404 " value {\n"
405 " string_value: \"127.0.0.1\"\n"
406 " }\n"
407 " }\n"
408 " fields {\n"
409 " key: \"ipPort\"\n"
410 " value {\n"
411 " number_value: 12345\n"
412 " }\n"
413 " }\n"
414 " fields {\n"
415 " key: \"type\"\n"
416 " value {\n"
417 " string_value: \"TYPE_IPV4\"\n"
418 " }\n"
419 " }\n"
420 " }\n"
421 " }\n"
422 "}\n"
423 "fields {\n"
424 " key: \"sequenceId\"\n"
425 " value {\n"
426 " number_value: 1\n"
427 " }\n"
428 "}\n"
429 "fields {\n"
430 " key: \"serviceName\"\n"
431 " value {\n"
432 " string_value: \"service_name\"\n"
433 " }\n"
434 "}\n"
435 "fields {\n"
436 " key: \"type\"\n"
437 " value {\n"
438 " string_value: \"CLIENT_HEADER\"\n"
439 " }\n"
440 "}\n";
441 EXPECT_EQ(output, pb_str);
442 }
443
444 TEST(EntryToJsonStructTest, ServerHeader) {
445 LoggingSink::Entry entry;
446 entry.call_id = 1234;
447 entry.sequence_id = 2;
448 entry.type = LoggingSink::Entry::EventType::kServerHeader;
449 entry.logger = LoggingSink::Entry::Logger::kServer;
450 entry.payload.metadata["key"] = "value";
451 entry.peer.type = LoggingSink::Entry::Address::Type::kIpv4;
452 entry.peer.address = "127.0.0.1";
453 entry.peer.ip_port = 1234;
454 entry.authority = "authority";
455 entry.service_name = "service_name";
456 entry.method_name = "method_name";
457
458 google::protobuf::Struct proto;
459 EntryToJsonStructProto(std::move(entry), &proto);
460 std::string output;
461 ::google::protobuf::TextFormat::PrintToString(proto, &output);
462 const char* pb_str =
463 "fields {\n"
464 " key: \"authority\"\n"
465 " value {\n"
466 " string_value: \"authority\"\n"
467 " }\n"
468 "}\n"
469 "fields {\n"
470 " key: \"callId\"\n"
471 " value {\n"
472 " string_value: \"00000000-0000-4000-8000-0000000004d2\"\n"
473 " }\n"
474 "}\n"
475 "fields {\n"
476 " key: \"logger\"\n"
477 " value {\n"
478 " string_value: \"SERVER\"\n"
479 " }\n"
480 "}\n"
481 "fields {\n"
482 " key: \"methodName\"\n"
483 " value {\n"
484 " string_value: \"method_name\"\n"
485 " }\n"
486 "}\n"
487 "fields {\n"
488 " key: \"payload\"\n"
489 " value {\n"
490 " struct_value {\n"
491 " fields {\n"
492 " key: \"metadata\"\n"
493 " value {\n"
494 " struct_value {\n"
495 " fields {\n"
496 " key: \"key\"\n"
497 " value {\n"
498 " string_value: \"value\"\n"
499 " }\n"
500 " }\n"
501 " }\n"
502 " }\n"
503 " }\n"
504 " }\n"
505 " }\n"
506 "}\n"
507 "fields {\n"
508 " key: \"peer\"\n"
509 " value {\n"
510 " struct_value {\n"
511 " fields {\n"
512 " key: \"address\"\n"
513 " value {\n"
514 " string_value: \"127.0.0.1\"\n"
515 " }\n"
516 " }\n"
517 " fields {\n"
518 " key: \"ipPort\"\n"
519 " value {\n"
520 " number_value: 1234\n"
521 " }\n"
522 " }\n"
523 " fields {\n"
524 " key: \"type\"\n"
525 " value {\n"
526 " string_value: \"TYPE_IPV4\"\n"
527 " }\n"
528 " }\n"
529 " }\n"
530 " }\n"
531 "}\n"
532 "fields {\n"
533 " key: \"sequenceId\"\n"
534 " value {\n"
535 " number_value: 2\n"
536 " }\n"
537 "}\n"
538 "fields {\n"
539 " key: \"serviceName\"\n"
540 " value {\n"
541 " string_value: \"service_name\"\n"
542 " }\n"
543 "}\n"
544 "fields {\n"
545 " key: \"type\"\n"
546 " value {\n"
547 " string_value: \"SERVER_HEADER\"\n"
548 " }\n"
549 "}\n";
550 EXPECT_EQ(output, pb_str);
551 }
552
553 TEST(EntryToJsonStructTest, ClientMessage) {
554 LoggingSink::Entry entry;
555 entry.call_id = 1234;
556 entry.sequence_id = 3;
557 entry.type = LoggingSink::Entry::EventType::kClientMessage;
558 entry.logger = LoggingSink::Entry::Logger::kClient;
559 entry.payload.message = "hello";
560 entry.payload.message_length = 5;
561 entry.peer.type = LoggingSink::Entry::Address::Type::kIpv4;
562 entry.peer.address = "127.0.0.1";
563 entry.peer.ip_port = 1234;
564 entry.authority = "authority";
565 entry.service_name = "service_name";
566 entry.method_name = "method_name";
567
568 google::protobuf::Struct proto;
569 EntryToJsonStructProto(std::move(entry), &proto);
570 std::string output;
571 ::google::protobuf::TextFormat::PrintToString(proto, &output);
572 std::string pb_str = absl::StrFormat(
573 "fields {\n"
574 " key: \"authority\"\n"
575 " value {\n"
576 " string_value: \"authority\"\n"
577 " }\n"
578 "}\n"
579 "fields {\n"
580 " key: \"callId\"\n"
581 " value {\n"
582 " string_value: \"00000000-0000-4000-8000-0000000004d2\"\n"
583 " }\n"
584 "}\n"
585 "fields {\n"
586 " key: \"logger\"\n"
587 " value {\n"
588 " string_value: \"CLIENT\"\n"
589 " }\n"
590 "}\n"
591 "fields {\n"
592 " key: \"methodName\"\n"
593 " value {\n"
594 " string_value: \"method_name\"\n"
595 " }\n"
596 "}\n"
597 "fields {\n"
598 " key: \"payload\"\n"
599 " value {\n"
600 " struct_value {\n"
601 " fields {\n"
602 " key: \"message\"\n"
603 " value {\n"
604 " string_value: \"%s\"\n"
605 " }\n"
606 " }\n"
607 " fields {\n"
608 " key: \"messageLength\"\n"
609 " value {\n"
610 " number_value: 5\n"
611 " }\n"
612 " }\n"
613 " }\n"
614 " }\n"
615 "}\n"
616 "fields {\n"
617 " key: \"peer\"\n"
618 " value {\n"
619 " struct_value {\n"
620 " fields {\n"
621 " key: \"address\"\n"
622 " value {\n"
623 " string_value: \"127.0.0.1\"\n"
624 " }\n"
625 " }\n"
626 " fields {\n"
627 " key: \"ipPort\"\n"
628 " value {\n"
629 " number_value: 1234\n"
630 " }\n"
631 " }\n"
632 " fields {\n"
633 " key: \"type\"\n"
634 " value {\n"
635 " string_value: \"TYPE_IPV4\"\n"
636 " }\n"
637 " }\n"
638 " }\n"
639 " }\n"
640 "}\n"
641 "fields {\n"
642 " key: \"sequenceId\"\n"
643 " value {\n"
644 " number_value: 3\n"
645 " }\n"
646 "}\n"
647 "fields {\n"
648 " key: \"serviceName\"\n"
649 " value {\n"
650 " string_value: \"service_name\"\n"
651 " }\n"
652 "}\n"
653 "fields {\n"
654 " key: \"type\"\n"
655 " value {\n"
656 " string_value: \"CLIENT_MESSAGE\"\n"
657 " }\n"
658 "}\n",
659 absl::Base64Escape("hello"));
660 EXPECT_EQ(output, pb_str);
661 }
662
663 TEST(EntryToJsonStructTest, ServerMessage) {
664 LoggingSink::Entry entry;
665 entry.call_id = 1234;
666 entry.sequence_id = 4;
667 entry.type = LoggingSink::Entry::EventType::kServerMessage;
668 entry.logger = LoggingSink::Entry::Logger::kServer;
669 entry.payload.message = "world";
670 entry.payload.message_length = 5;
671 entry.peer.type = LoggingSink::Entry::Address::Type::kIpv4;
672 entry.peer.address = "127.0.0.1";
673 entry.peer.ip_port = 12345;
674 entry.authority = "authority";
675 entry.service_name = "service_name";
676 entry.method_name = "method_name";
677
678 google::protobuf::Struct proto;
679 EntryToJsonStructProto(std::move(entry), &proto);
680 std::string output;
681 ::google::protobuf::TextFormat::PrintToString(proto, &output);
682 std::string pb_str = absl::StrFormat(
683 "fields {\n"
684 " key: \"authority\"\n"
685 " value {\n"
686 " string_value: \"authority\"\n"
687 " }\n"
688 "}\n"
689 "fields {\n"
690 " key: \"callId\"\n"
691 " value {\n"
692 " string_value: \"00000000-0000-4000-8000-0000000004d2\"\n"
693 " }\n"
694 "}\n"
695 "fields {\n"
696 " key: \"logger\"\n"
697 " value {\n"
698 " string_value: \"SERVER\"\n"
699 " }\n"
700 "}\n"
701 "fields {\n"
702 " key: \"methodName\"\n"
703 " value {\n"
704 " string_value: \"method_name\"\n"
705 " }\n"
706 "}\n"
707 "fields {\n"
708 " key: \"payload\"\n"
709 " value {\n"
710 " struct_value {\n"
711 " fields {\n"
712 " key: \"message\"\n"
713 " value {\n"
714 " string_value: \"%s\"\n"
715 " }\n"
716 " }\n"
717 " fields {\n"
718 " key: \"messageLength\"\n"
719 " value {\n"
720 " number_value: 5\n"
721 " }\n"
722 " }\n"
723 " }\n"
724 " }\n"
725 "}\n"
726 "fields {\n"
727 " key: \"peer\"\n"
728 " value {\n"
729 " struct_value {\n"
730 " fields {\n"
731 " key: \"address\"\n"
732 " value {\n"
733 " string_value: \"127.0.0.1\"\n"
734 " }\n"
735 " }\n"
736 " fields {\n"
737 " key: \"ipPort\"\n"
738 " value {\n"
739 " number_value: 12345\n"
740 " }\n"
741 " }\n"
742 " fields {\n"
743 " key: \"type\"\n"
744 " value {\n"
745 " string_value: \"TYPE_IPV4\"\n"
746 " }\n"
747 " }\n"
748 " }\n"
749 " }\n"
750 "}\n"
751 "fields {\n"
752 " key: \"sequenceId\"\n"
753 " value {\n"
754 " number_value: 4\n"
755 " }\n"
756 "}\n"
757 "fields {\n"
758 " key: \"serviceName\"\n"
759 " value {\n"
760 " string_value: \"service_name\"\n"
761 " }\n"
762 "}\n"
763 "fields {\n"
764 " key: \"type\"\n"
765 " value {\n"
766 " string_value: \"SERVER_MESSAGE\"\n"
767 " }\n"
768 "}\n",
769 absl::Base64Escape("world"));
770 EXPECT_EQ(output, pb_str);
771 }
772
773 TEST(EntryToJsonStructTest, ClientHalfClose) {
774 LoggingSink::Entry entry;
775 entry.call_id = 1234;
776 entry.sequence_id = 5;
777 entry.type = LoggingSink::Entry::EventType::kClientHalfClose;
778 entry.logger = LoggingSink::Entry::Logger::kClient;
779 entry.peer.type = LoggingSink::Entry::Address::Type::kIpv4;
780 entry.peer.address = "127.0.0.1";
781 entry.peer.ip_port = 1234;
782 entry.authority = "authority";
783 entry.service_name = "service_name";
784 entry.method_name = "method_name";
785
786 google::protobuf::Struct proto;
787 EntryToJsonStructProto(std::move(entry), &proto);
788 std::string output;
789 ::google::protobuf::TextFormat::PrintToString(proto, &output);
790 const char* pb_str =
791 "fields {\n"
792 " key: \"authority\"\n"
793 " value {\n"
794 " string_value: \"authority\"\n"
795 " }\n"
796 "}\n"
797 "fields {\n"
798 " key: \"callId\"\n"
799 " value {\n"
800 " string_value: \"00000000-0000-4000-8000-0000000004d2\"\n"
801 " }\n"
802 "}\n"
803 "fields {\n"
804 " key: \"logger\"\n"
805 " value {\n"
806 " string_value: \"CLIENT\"\n"
807 " }\n"
808 "}\n"
809 "fields {\n"
810 " key: \"methodName\"\n"
811 " value {\n"
812 " string_value: \"method_name\"\n"
813 " }\n"
814 "}\n"
815 "fields {\n"
816 " key: \"payload\"\n"
817 " value {\n"
818 " struct_value {\n"
819 " }\n"
820 " }\n"
821 "}\n"
822 "fields {\n"
823 " key: \"peer\"\n"
824 " value {\n"
825 " struct_value {\n"
826 " fields {\n"
827 " key: \"address\"\n"
828 " value {\n"
829 " string_value: \"127.0.0.1\"\n"
830 " }\n"
831 " }\n"
832 " fields {\n"
833 " key: \"ipPort\"\n"
834 " value {\n"
835 " number_value: 1234\n"
836 " }\n"
837 " }\n"
838 " fields {\n"
839 " key: \"type\"\n"
840 " value {\n"
841 " string_value: \"TYPE_IPV4\"\n"
842 " }\n"
843 " }\n"
844 " }\n"
845 " }\n"
846 "}\n"
847 "fields {\n"
848 " key: \"sequenceId\"\n"
849 " value {\n"
850 " number_value: 5\n"
851 " }\n"
852 "}\n"
853 "fields {\n"
854 " key: \"serviceName\"\n"
855 " value {\n"
856 " string_value: \"service_name\"\n"
857 " }\n"
858 "}\n"
859 "fields {\n"
860 " key: \"type\"\n"
861 " value {\n"
862 " string_value: \"CLIENT_HALF_CLOSE\"\n"
863 " }\n"
864 "}\n";
865 EXPECT_EQ(output, pb_str);
866 }
867
868 TEST(EntryToJsonStructTest, ServerTrailer) {
869 LoggingSink::Entry entry;
870 entry.call_id = 1234;
871 entry.sequence_id = 6;
872 entry.type = LoggingSink::Entry::EventType::kServerTrailer;
873 entry.logger = LoggingSink::Entry::Logger::kServer;
874 entry.payload.metadata["key"] = "value";
875 entry.peer.type = LoggingSink::Entry::Address::Type::kIpv4;
876 entry.peer.address = "127.0.0.1";
877 entry.peer.ip_port = 1234;
878 entry.authority = "authority";
879 entry.service_name = "service_name";
880 entry.method_name = "method_name";
881
882 google::protobuf::Struct proto;
883 EntryToJsonStructProto(std::move(entry), &proto);
884 std::string output;
885 ::google::protobuf::TextFormat::PrintToString(proto, &output);
886 const char* pb_str =
887 "fields {\n"
888 " key: \"authority\"\n"
889 " value {\n"
890 " string_value: \"authority\"\n"
891 " }\n"
892 "}\n"
893 "fields {\n"
894 " key: \"callId\"\n"
895 " value {\n"
896 " string_value: \"00000000-0000-4000-8000-0000000004d2\"\n"
897 " }\n"
898 "}\n"
899 "fields {\n"
900 " key: \"logger\"\n"
901 " value {\n"
902 " string_value: \"SERVER\"\n"
903 " }\n"
904 "}\n"
905 "fields {\n"
906 " key: \"methodName\"\n"
907 " value {\n"
908 " string_value: \"method_name\"\n"
909 " }\n"
910 "}\n"
911 "fields {\n"
912 " key: \"payload\"\n"
913 " value {\n"
914 " struct_value {\n"
915 " fields {\n"
916 " key: \"metadata\"\n"
917 " value {\n"
918 " struct_value {\n"
919 " fields {\n"
920 " key: \"key\"\n"
921 " value {\n"
922 " string_value: \"value\"\n"
923 " }\n"
924 " }\n"
925 " }\n"
926 " }\n"
927 " }\n"
928 " }\n"
929 " }\n"
930 "}\n"
931 "fields {\n"
932 " key: \"peer\"\n"
933 " value {\n"
934 " struct_value {\n"
935 " fields {\n"
936 " key: \"address\"\n"
937 " value {\n"
938 " string_value: \"127.0.0.1\"\n"
939 " }\n"
940 " }\n"
941 " fields {\n"
942 " key: \"ipPort\"\n"
943 " value {\n"
944 " number_value: 1234\n"
945 " }\n"
946 " }\n"
947 " fields {\n"
948 " key: \"type\"\n"
949 " value {\n"
950 " string_value: \"TYPE_IPV4\"\n"
951 " }\n"
952 " }\n"
953 " }\n"
954 " }\n"
955 "}\n"
956 "fields {\n"
957 " key: \"sequenceId\"\n"
958 " value {\n"
959 " number_value: 6\n"
960 " }\n"
961 "}\n"
962 "fields {\n"
963 " key: \"serviceName\"\n"
964 " value {\n"
965 " string_value: \"service_name\"\n"
966 " }\n"
967 "}\n"
968 "fields {\n"
969 " key: \"type\"\n"
970 " value {\n"
971 " string_value: \"SERVER_TRAILER\"\n"
972 " }\n"
973 "}\n";
974 EXPECT_EQ(output, pb_str);
975 }
976
977 TEST(EntryToJsonStructTest, Cancel) {
978 LoggingSink::Entry entry;
979 entry.call_id = 1234;
980 entry.sequence_id = 7;
981 entry.type = LoggingSink::Entry::EventType::kCancel;
982 entry.logger = LoggingSink::Entry::Logger::kClient;
983 entry.peer.type = LoggingSink::Entry::Address::Type::kIpv4;
984 entry.peer.address = "127.0.0.1";
985 entry.peer.ip_port = 1234;
986 entry.authority = "authority";
987 entry.service_name = "service_name";
988 entry.method_name = "method_name";
989
990 google::protobuf::Struct proto;
991 EntryToJsonStructProto(std::move(entry), &proto);
992 std::string output;
993 ::google::protobuf::TextFormat::PrintToString(proto, &output);
994 const char* pb_str =
995 "fields {\n"
996 " key: \"authority\"\n"
997 " value {\n"
998 " string_value: \"authority\"\n"
999 " }\n"
1000 "}\n"
1001 "fields {\n"
1002 " key: \"callId\"\n"
1003 " value {\n"
1004 " string_value: \"00000000-0000-4000-8000-0000000004d2\"\n"
1005 " }\n"
1006 "}\n"
1007 "fields {\n"
1008 " key: \"logger\"\n"
1009 " value {\n"
1010 " string_value: \"CLIENT\"\n"
1011 " }\n"
1012 "}\n"
1013 "fields {\n"
1014 " key: \"methodName\"\n"
1015 " value {\n"
1016 " string_value: \"method_name\"\n"
1017 " }\n"
1018 "}\n"
1019 "fields {\n"
1020 " key: \"payload\"\n"
1021 " value {\n"
1022 " struct_value {\n"
1023 " }\n"
1024 " }\n"
1025 "}\n"
1026 "fields {\n"
1027 " key: \"peer\"\n"
1028 " value {\n"
1029 " struct_value {\n"
1030 " fields {\n"
1031 " key: \"address\"\n"
1032 " value {\n"
1033 " string_value: \"127.0.0.1\"\n"
1034 " }\n"
1035 " }\n"
1036 " fields {\n"
1037 " key: \"ipPort\"\n"
1038 " value {\n"
1039 " number_value: 1234\n"
1040 " }\n"
1041 " }\n"
1042 " fields {\n"
1043 " key: \"type\"\n"
1044 " value {\n"
1045 " string_value: \"TYPE_IPV4\"\n"
1046 " }\n"
1047 " }\n"
1048 " }\n"
1049 " }\n"
1050 "}\n"
1051 "fields {\n"
1052 " key: \"sequenceId\"\n"
1053 " value {\n"
1054 " number_value: 7\n"
1055 " }\n"
1056 "}\n"
1057 "fields {\n"
1058 " key: \"serviceName\"\n"
1059 " value {\n"
1060 " string_value: \"service_name\"\n"
1061 " }\n"
1062 "}\n"
1063 "fields {\n"
1064 " key: \"type\"\n"
1065 " value {\n"
1066 " string_value: \"CANCEL\"\n"
1067 " }\n"
1068 "}\n";
1069 EXPECT_EQ(output, pb_str);
1070 }
1071
1072 } // namespace
1073
1074 } // namespace internal
1075 } // namespace grpc
1076
1077 int main(int argc, char** argv) {
1078 grpc::testing::TestEnvironment env(&argc, argv);
1079 ::testing::InitGoogleTest(&argc, argv);
1080 return RUN_ALL_TESTS();
1081 }
1082