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