method_logger_test.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542
  1. /*
  2. *
  3. * Copyright 2018 gRPC authors.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. package binarylog
  19. import (
  20. "bytes"
  21. "fmt"
  22. "net"
  23. "testing"
  24. "time"
  25. "github.com/golang/protobuf/proto"
  26. dpb "github.com/golang/protobuf/ptypes/duration"
  27. pb "google.golang.org/grpc/binarylog/grpc_binarylog_v1"
  28. "google.golang.org/grpc/codes"
  29. "google.golang.org/grpc/status"
  30. )
  31. func TestLog(t *testing.T) {
  32. idGen.reset()
  33. ml := newMethodLogger(10, 10)
  34. // Set sink to testing buffer.
  35. buf := bytes.NewBuffer(nil)
  36. ml.sink = newWriterSink(buf)
  37. addr := "1.2.3.4"
  38. port := 790
  39. tcpAddr, _ := net.ResolveTCPAddr("tcp", fmt.Sprintf("%v:%d", addr, port))
  40. addr6 := "2001:1db8:85a3::8a2e:1370:7334"
  41. port6 := 796
  42. tcpAddr6, _ := net.ResolveTCPAddr("tcp", fmt.Sprintf("[%v]:%d", addr6, port6))
  43. testProtoMsg := &pb.Message{
  44. Length: 1,
  45. Data: []byte{'a'},
  46. }
  47. testProtoBytes, _ := proto.Marshal(testProtoMsg)
  48. testCases := []struct {
  49. config LogEntryConfig
  50. want *pb.GrpcLogEntry
  51. }{
  52. {
  53. config: &ClientHeader{
  54. OnClientSide: false,
  55. Header: map[string][]string{
  56. "a": {"b", "bb"},
  57. },
  58. MethodName: "testservice/testmethod",
  59. Authority: "test.service.io",
  60. Timeout: 2*time.Second + 3*time.Nanosecond,
  61. PeerAddr: tcpAddr,
  62. },
  63. want: &pb.GrpcLogEntry{
  64. Timestamp: nil,
  65. CallId: 1,
  66. SequenceIdWithinCall: 0,
  67. Type: pb.GrpcLogEntry_EVENT_TYPE_CLIENT_HEADER,
  68. Logger: pb.GrpcLogEntry_LOGGER_SERVER,
  69. Payload: &pb.GrpcLogEntry_ClientHeader{
  70. ClientHeader: &pb.ClientHeader{
  71. Metadata: &pb.Metadata{
  72. Entry: []*pb.MetadataEntry{
  73. {Key: "a", Value: []byte{'b'}},
  74. {Key: "a", Value: []byte{'b', 'b'}},
  75. },
  76. },
  77. MethodName: "testservice/testmethod",
  78. Authority: "test.service.io",
  79. Timeout: &dpb.Duration{
  80. Seconds: 2,
  81. Nanos: 3,
  82. },
  83. },
  84. },
  85. PayloadTruncated: false,
  86. Peer: &pb.Address{
  87. Type: pb.Address_TYPE_IPV4,
  88. Address: addr,
  89. IpPort: uint32(port),
  90. },
  91. },
  92. },
  93. {
  94. config: &ClientHeader{
  95. OnClientSide: false,
  96. MethodName: "testservice/testmethod",
  97. Authority: "test.service.io",
  98. },
  99. want: &pb.GrpcLogEntry{
  100. Timestamp: nil,
  101. CallId: 1,
  102. SequenceIdWithinCall: 0,
  103. Type: pb.GrpcLogEntry_EVENT_TYPE_CLIENT_HEADER,
  104. Logger: pb.GrpcLogEntry_LOGGER_SERVER,
  105. Payload: &pb.GrpcLogEntry_ClientHeader{
  106. ClientHeader: &pb.ClientHeader{
  107. Metadata: &pb.Metadata{},
  108. MethodName: "testservice/testmethod",
  109. Authority: "test.service.io",
  110. },
  111. },
  112. PayloadTruncated: false,
  113. },
  114. },
  115. {
  116. config: &ServerHeader{
  117. OnClientSide: true,
  118. Header: map[string][]string{
  119. "a": {"b", "bb"},
  120. },
  121. PeerAddr: tcpAddr6,
  122. },
  123. want: &pb.GrpcLogEntry{
  124. Timestamp: nil,
  125. CallId: 1,
  126. SequenceIdWithinCall: 0,
  127. Type: pb.GrpcLogEntry_EVENT_TYPE_SERVER_HEADER,
  128. Logger: pb.GrpcLogEntry_LOGGER_CLIENT,
  129. Payload: &pb.GrpcLogEntry_ServerHeader{
  130. ServerHeader: &pb.ServerHeader{
  131. Metadata: &pb.Metadata{
  132. Entry: []*pb.MetadataEntry{
  133. {Key: "a", Value: []byte{'b'}},
  134. {Key: "a", Value: []byte{'b', 'b'}},
  135. },
  136. },
  137. },
  138. },
  139. PayloadTruncated: false,
  140. Peer: &pb.Address{
  141. Type: pb.Address_TYPE_IPV6,
  142. Address: addr6,
  143. IpPort: uint32(port6),
  144. },
  145. },
  146. },
  147. {
  148. config: &ClientMessage{
  149. OnClientSide: true,
  150. Message: testProtoMsg,
  151. },
  152. want: &pb.GrpcLogEntry{
  153. Timestamp: nil,
  154. CallId: 1,
  155. SequenceIdWithinCall: 0,
  156. Type: pb.GrpcLogEntry_EVENT_TYPE_CLIENT_MESSAGE,
  157. Logger: pb.GrpcLogEntry_LOGGER_CLIENT,
  158. Payload: &pb.GrpcLogEntry_Message{
  159. Message: &pb.Message{
  160. Length: uint32(len(testProtoBytes)),
  161. Data: testProtoBytes,
  162. },
  163. },
  164. PayloadTruncated: false,
  165. Peer: nil,
  166. },
  167. },
  168. {
  169. config: &ServerMessage{
  170. OnClientSide: false,
  171. Message: testProtoMsg,
  172. },
  173. want: &pb.GrpcLogEntry{
  174. Timestamp: nil,
  175. CallId: 1,
  176. SequenceIdWithinCall: 0,
  177. Type: pb.GrpcLogEntry_EVENT_TYPE_SERVER_MESSAGE,
  178. Logger: pb.GrpcLogEntry_LOGGER_SERVER,
  179. Payload: &pb.GrpcLogEntry_Message{
  180. Message: &pb.Message{
  181. Length: uint32(len(testProtoBytes)),
  182. Data: testProtoBytes,
  183. },
  184. },
  185. PayloadTruncated: false,
  186. Peer: nil,
  187. },
  188. },
  189. {
  190. config: &ClientHalfClose{
  191. OnClientSide: false,
  192. },
  193. want: &pb.GrpcLogEntry{
  194. Timestamp: nil,
  195. CallId: 1,
  196. SequenceIdWithinCall: 0,
  197. Type: pb.GrpcLogEntry_EVENT_TYPE_CLIENT_HALF_CLOSE,
  198. Logger: pb.GrpcLogEntry_LOGGER_SERVER,
  199. Payload: nil,
  200. PayloadTruncated: false,
  201. Peer: nil,
  202. },
  203. },
  204. {
  205. config: &ServerTrailer{
  206. OnClientSide: true,
  207. Err: status.Errorf(codes.Unavailable, "test"),
  208. PeerAddr: tcpAddr,
  209. },
  210. want: &pb.GrpcLogEntry{
  211. Timestamp: nil,
  212. CallId: 1,
  213. SequenceIdWithinCall: 0,
  214. Type: pb.GrpcLogEntry_EVENT_TYPE_SERVER_TRAILER,
  215. Logger: pb.GrpcLogEntry_LOGGER_CLIENT,
  216. Payload: &pb.GrpcLogEntry_Trailer{
  217. Trailer: &pb.Trailer{
  218. Metadata: &pb.Metadata{},
  219. StatusCode: uint32(codes.Unavailable),
  220. StatusMessage: "test",
  221. StatusDetails: nil,
  222. },
  223. },
  224. PayloadTruncated: false,
  225. Peer: &pb.Address{
  226. Type: pb.Address_TYPE_IPV4,
  227. Address: addr,
  228. IpPort: uint32(port),
  229. },
  230. },
  231. },
  232. { // Err is nil, Log OK status.
  233. config: &ServerTrailer{
  234. OnClientSide: true,
  235. },
  236. want: &pb.GrpcLogEntry{
  237. Timestamp: nil,
  238. CallId: 1,
  239. SequenceIdWithinCall: 0,
  240. Type: pb.GrpcLogEntry_EVENT_TYPE_SERVER_TRAILER,
  241. Logger: pb.GrpcLogEntry_LOGGER_CLIENT,
  242. Payload: &pb.GrpcLogEntry_Trailer{
  243. Trailer: &pb.Trailer{
  244. Metadata: &pb.Metadata{},
  245. StatusCode: uint32(codes.OK),
  246. StatusMessage: "",
  247. StatusDetails: nil,
  248. },
  249. },
  250. PayloadTruncated: false,
  251. Peer: nil,
  252. },
  253. },
  254. {
  255. config: &Cancel{
  256. OnClientSide: true,
  257. },
  258. want: &pb.GrpcLogEntry{
  259. Timestamp: nil,
  260. CallId: 1,
  261. SequenceIdWithinCall: 0,
  262. Type: pb.GrpcLogEntry_EVENT_TYPE_CANCEL,
  263. Logger: pb.GrpcLogEntry_LOGGER_CLIENT,
  264. Payload: nil,
  265. PayloadTruncated: false,
  266. Peer: nil,
  267. },
  268. },
  269. // gRPC headers should be omitted.
  270. {
  271. config: &ClientHeader{
  272. OnClientSide: false,
  273. Header: map[string][]string{
  274. "grpc-reserved": {"to be omitted"},
  275. ":authority": {"to be omitted"},
  276. "a": {"b", "bb"},
  277. },
  278. },
  279. want: &pb.GrpcLogEntry{
  280. Timestamp: nil,
  281. CallId: 1,
  282. SequenceIdWithinCall: 0,
  283. Type: pb.GrpcLogEntry_EVENT_TYPE_CLIENT_HEADER,
  284. Logger: pb.GrpcLogEntry_LOGGER_SERVER,
  285. Payload: &pb.GrpcLogEntry_ClientHeader{
  286. ClientHeader: &pb.ClientHeader{
  287. Metadata: &pb.Metadata{
  288. Entry: []*pb.MetadataEntry{
  289. {Key: "a", Value: []byte{'b'}},
  290. {Key: "a", Value: []byte{'b', 'b'}},
  291. },
  292. },
  293. },
  294. },
  295. PayloadTruncated: false,
  296. },
  297. },
  298. {
  299. config: &ServerHeader{
  300. OnClientSide: true,
  301. Header: map[string][]string{
  302. "grpc-reserved": {"to be omitted"},
  303. ":authority": {"to be omitted"},
  304. "a": {"b", "bb"},
  305. },
  306. },
  307. want: &pb.GrpcLogEntry{
  308. Timestamp: nil,
  309. CallId: 1,
  310. SequenceIdWithinCall: 0,
  311. Type: pb.GrpcLogEntry_EVENT_TYPE_SERVER_HEADER,
  312. Logger: pb.GrpcLogEntry_LOGGER_CLIENT,
  313. Payload: &pb.GrpcLogEntry_ServerHeader{
  314. ServerHeader: &pb.ServerHeader{
  315. Metadata: &pb.Metadata{
  316. Entry: []*pb.MetadataEntry{
  317. {Key: "a", Value: []byte{'b'}},
  318. {Key: "a", Value: []byte{'b', 'b'}},
  319. },
  320. },
  321. },
  322. },
  323. PayloadTruncated: false,
  324. },
  325. },
  326. }
  327. for i, tc := range testCases {
  328. buf.Reset()
  329. tc.want.SequenceIdWithinCall = uint64(i + 1)
  330. ml.Log(tc.config)
  331. inSink := new(pb.GrpcLogEntry)
  332. if err := proto.Unmarshal(buf.Bytes()[4:], inSink); err != nil {
  333. t.Errorf("failed to unmarshal bytes in sink to proto: %v", err)
  334. continue
  335. }
  336. inSink.Timestamp = nil // Strip timestamp before comparing.
  337. if !proto.Equal(inSink, tc.want) {
  338. t.Errorf("Log(%+v), in sink: %+v, want %+v", tc.config, inSink, tc.want)
  339. }
  340. }
  341. }
  342. func TestTruncateMetadataNotTruncated(t *testing.T) {
  343. testCases := []struct {
  344. ml *MethodLogger
  345. mpPb *pb.Metadata
  346. }{
  347. {
  348. ml: newMethodLogger(maxUInt, maxUInt),
  349. mpPb: &pb.Metadata{
  350. Entry: []*pb.MetadataEntry{
  351. {Key: "", Value: []byte{1}},
  352. },
  353. },
  354. },
  355. {
  356. ml: newMethodLogger(2, maxUInt),
  357. mpPb: &pb.Metadata{
  358. Entry: []*pb.MetadataEntry{
  359. {Key: "", Value: []byte{1}},
  360. },
  361. },
  362. },
  363. {
  364. ml: newMethodLogger(1, maxUInt),
  365. mpPb: &pb.Metadata{
  366. Entry: []*pb.MetadataEntry{
  367. {Key: "", Value: nil},
  368. },
  369. },
  370. },
  371. {
  372. ml: newMethodLogger(2, maxUInt),
  373. mpPb: &pb.Metadata{
  374. Entry: []*pb.MetadataEntry{
  375. {Key: "", Value: []byte{1, 1}},
  376. },
  377. },
  378. },
  379. {
  380. ml: newMethodLogger(2, maxUInt),
  381. mpPb: &pb.Metadata{
  382. Entry: []*pb.MetadataEntry{
  383. {Key: "", Value: []byte{1}},
  384. {Key: "", Value: []byte{1}},
  385. },
  386. },
  387. },
  388. // "grpc-trace-bin" is kept in log but not counted towards the size
  389. // limit.
  390. {
  391. ml: newMethodLogger(1, maxUInt),
  392. mpPb: &pb.Metadata{
  393. Entry: []*pb.MetadataEntry{
  394. {Key: "", Value: []byte{1}},
  395. {Key: "grpc-trace-bin", Value: []byte("some.trace.key")},
  396. },
  397. },
  398. },
  399. }
  400. for i, tc := range testCases {
  401. truncated := tc.ml.truncateMetadata(tc.mpPb)
  402. if truncated {
  403. t.Errorf("test case %v, returned truncated, want not truncated", i)
  404. }
  405. }
  406. }
  407. func TestTruncateMetadataTruncated(t *testing.T) {
  408. testCases := []struct {
  409. ml *MethodLogger
  410. mpPb *pb.Metadata
  411. entryLen int
  412. }{
  413. {
  414. ml: newMethodLogger(2, maxUInt),
  415. mpPb: &pb.Metadata{
  416. Entry: []*pb.MetadataEntry{
  417. {Key: "", Value: []byte{1, 1, 1}},
  418. },
  419. },
  420. entryLen: 0,
  421. },
  422. {
  423. ml: newMethodLogger(2, maxUInt),
  424. mpPb: &pb.Metadata{
  425. Entry: []*pb.MetadataEntry{
  426. {Key: "", Value: []byte{1}},
  427. {Key: "", Value: []byte{1}},
  428. {Key: "", Value: []byte{1}},
  429. },
  430. },
  431. entryLen: 2,
  432. },
  433. {
  434. ml: newMethodLogger(2, maxUInt),
  435. mpPb: &pb.Metadata{
  436. Entry: []*pb.MetadataEntry{
  437. {Key: "", Value: []byte{1, 1}},
  438. {Key: "", Value: []byte{1}},
  439. },
  440. },
  441. entryLen: 1,
  442. },
  443. {
  444. ml: newMethodLogger(2, maxUInt),
  445. mpPb: &pb.Metadata{
  446. Entry: []*pb.MetadataEntry{
  447. {Key: "", Value: []byte{1}},
  448. {Key: "", Value: []byte{1, 1}},
  449. },
  450. },
  451. entryLen: 1,
  452. },
  453. }
  454. for i, tc := range testCases {
  455. truncated := tc.ml.truncateMetadata(tc.mpPb)
  456. if !truncated {
  457. t.Errorf("test case %v, returned not truncated, want truncated", i)
  458. continue
  459. }
  460. if len(tc.mpPb.Entry) != tc.entryLen {
  461. t.Errorf("test case %v, entry length: %v, want: %v", i, len(tc.mpPb.Entry), tc.entryLen)
  462. }
  463. }
  464. }
  465. func TestTruncateMessageNotTruncated(t *testing.T) {
  466. testCases := []struct {
  467. ml *MethodLogger
  468. msgPb *pb.Message
  469. }{
  470. {
  471. ml: newMethodLogger(maxUInt, maxUInt),
  472. msgPb: &pb.Message{
  473. Data: []byte{1},
  474. },
  475. },
  476. {
  477. ml: newMethodLogger(maxUInt, 3),
  478. msgPb: &pb.Message{
  479. Data: []byte{1, 1},
  480. },
  481. },
  482. {
  483. ml: newMethodLogger(maxUInt, 2),
  484. msgPb: &pb.Message{
  485. Data: []byte{1, 1},
  486. },
  487. },
  488. }
  489. for i, tc := range testCases {
  490. truncated := tc.ml.truncateMessage(tc.msgPb)
  491. if truncated {
  492. t.Errorf("test case %v, returned truncated, want not truncated", i)
  493. }
  494. }
  495. }
  496. func TestTruncateMessageTruncated(t *testing.T) {
  497. testCases := []struct {
  498. ml *MethodLogger
  499. msgPb *pb.Message
  500. oldLength uint32
  501. }{
  502. {
  503. ml: newMethodLogger(maxUInt, 2),
  504. msgPb: &pb.Message{
  505. Length: 3,
  506. Data: []byte{1, 1, 1},
  507. },
  508. oldLength: 3,
  509. },
  510. }
  511. for i, tc := range testCases {
  512. truncated := tc.ml.truncateMessage(tc.msgPb)
  513. if !truncated {
  514. t.Errorf("test case %v, returned not truncated, want truncated", i)
  515. continue
  516. }
  517. if len(tc.msgPb.Data) != int(tc.ml.messageMaxLen) {
  518. t.Errorf("test case %v, message length: %v, want: %v", i, len(tc.msgPb.Data), tc.ml.messageMaxLen)
  519. }
  520. if tc.msgPb.Length != tc.oldLength {
  521. t.Errorf("test case %v, message.Length field: %v, want: %v", i, tc.msgPb.Length, tc.oldLength)
  522. }
  523. }
  524. }