xref: /aosp_15_r20/external/grpc-grpc/test/cpp/ext/gcp/observability_logging_sink_test.cc (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
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