github.com/rhatdan/docker@v0.7.7-0.20180119204836-47a0dcbcd20a/daemon/logger/splunk/splunk_test.go (about) 1 package splunk 2 3 import ( 4 "compress/gzip" 5 "context" 6 "fmt" 7 "os" 8 "runtime" 9 "testing" 10 "time" 11 12 "github.com/docker/docker/daemon/logger" 13 "github.com/stretchr/testify/require" 14 ) 15 16 // Validate options 17 func TestValidateLogOpt(t *testing.T) { 18 err := ValidateLogOpt(map[string]string{ 19 splunkURLKey: "http://127.0.0.1", 20 splunkTokenKey: "2160C7EF-2CE9-4307-A180-F852B99CF417", 21 splunkSourceKey: "mysource", 22 splunkSourceTypeKey: "mysourcetype", 23 splunkIndexKey: "myindex", 24 splunkCAPathKey: "/usr/cert.pem", 25 splunkCANameKey: "ca_name", 26 splunkInsecureSkipVerifyKey: "true", 27 splunkFormatKey: "json", 28 splunkVerifyConnectionKey: "true", 29 splunkGzipCompressionKey: "true", 30 splunkGzipCompressionLevelKey: "1", 31 envKey: "a", 32 envRegexKey: "^foo", 33 labelsKey: "b", 34 tagKey: "c", 35 }) 36 if err != nil { 37 t.Fatal(err) 38 } 39 40 err = ValidateLogOpt(map[string]string{ 41 "not-supported-option": "a", 42 }) 43 if err == nil { 44 t.Fatal("Expecting error on unsupported options") 45 } 46 } 47 48 // Driver require user to specify required options 49 func TestNewMissedConfig(t *testing.T) { 50 info := logger.Info{ 51 Config: map[string]string{}, 52 } 53 _, err := New(info) 54 if err == nil { 55 t.Fatal("Logger driver should fail when no required parameters specified") 56 } 57 } 58 59 // Driver require user to specify splunk-url 60 func TestNewMissedUrl(t *testing.T) { 61 info := logger.Info{ 62 Config: map[string]string{ 63 splunkTokenKey: "4642492F-D8BD-47F1-A005-0C08AE4657DF", 64 }, 65 } 66 _, err := New(info) 67 if err.Error() != "splunk: splunk-url is expected" { 68 t.Fatal("Logger driver should fail when no required parameters specified") 69 } 70 } 71 72 // Driver require user to specify splunk-token 73 func TestNewMissedToken(t *testing.T) { 74 info := logger.Info{ 75 Config: map[string]string{ 76 splunkURLKey: "http://127.0.0.1:8088", 77 }, 78 } 79 _, err := New(info) 80 if err.Error() != "splunk: splunk-token is expected" { 81 t.Fatal("Logger driver should fail when no required parameters specified") 82 } 83 } 84 85 // Test default settings 86 func TestDefault(t *testing.T) { 87 hec := NewHTTPEventCollectorMock(t) 88 89 go hec.Serve() 90 91 info := logger.Info{ 92 Config: map[string]string{ 93 splunkURLKey: hec.URL(), 94 splunkTokenKey: hec.token, 95 }, 96 ContainerID: "containeriid", 97 ContainerName: "container_name", 98 ContainerImageID: "contaimageid", 99 ContainerImageName: "container_image_name", 100 } 101 102 hostname, err := info.Hostname() 103 if err != nil { 104 t.Fatal(err) 105 } 106 107 loggerDriver, err := New(info) 108 if err != nil { 109 t.Fatal(err) 110 } 111 112 if loggerDriver.Name() != driverName { 113 t.Fatal("Unexpected logger driver name") 114 } 115 116 if !hec.connectionVerified { 117 t.Fatal("By default connection should be verified") 118 } 119 120 splunkLoggerDriver, ok := loggerDriver.(*splunkLoggerInline) 121 if !ok { 122 t.Fatal("Unexpected Splunk Logging Driver type") 123 } 124 125 if splunkLoggerDriver.url != hec.URL()+"/services/collector/event/1.0" || 126 splunkLoggerDriver.auth != "Splunk "+hec.token || 127 splunkLoggerDriver.nullMessage.Host != hostname || 128 splunkLoggerDriver.nullMessage.Source != "" || 129 splunkLoggerDriver.nullMessage.SourceType != "" || 130 splunkLoggerDriver.nullMessage.Index != "" || 131 splunkLoggerDriver.gzipCompression || 132 splunkLoggerDriver.postMessagesFrequency != defaultPostMessagesFrequency || 133 splunkLoggerDriver.postMessagesBatchSize != defaultPostMessagesBatchSize || 134 splunkLoggerDriver.bufferMaximum != defaultBufferMaximum || 135 cap(splunkLoggerDriver.stream) != defaultStreamChannelSize { 136 t.Fatal("Found not default values setup in Splunk Logging Driver.") 137 } 138 139 message1Time := time.Now() 140 if err := loggerDriver.Log(&logger.Message{Line: []byte("{\"a\":\"b\"}"), Source: "stdout", Timestamp: message1Time}); err != nil { 141 t.Fatal(err) 142 } 143 message2Time := time.Now() 144 if err := loggerDriver.Log(&logger.Message{Line: []byte("notajson"), Source: "stdout", Timestamp: message2Time}); err != nil { 145 t.Fatal(err) 146 } 147 148 err = loggerDriver.Close() 149 if err != nil { 150 t.Fatal(err) 151 } 152 153 if len(hec.messages) != 2 { 154 t.Fatal("Expected two messages") 155 } 156 157 if *hec.gzipEnabled { 158 t.Fatal("Gzip should not be used") 159 } 160 161 message1 := hec.messages[0] 162 if message1.Time != fmt.Sprintf("%f", float64(message1Time.UnixNano())/float64(time.Second)) || 163 message1.Host != hostname || 164 message1.Source != "" || 165 message1.SourceType != "" || 166 message1.Index != "" { 167 t.Fatalf("Unexpected values of message 1 %v", message1) 168 } 169 170 if event, err := message1.EventAsMap(); err != nil { 171 t.Fatal(err) 172 } else { 173 if event["line"] != "{\"a\":\"b\"}" || 174 event["source"] != "stdout" || 175 event["tag"] != "containeriid" || 176 len(event) != 3 { 177 t.Fatalf("Unexpected event in message %v", event) 178 } 179 } 180 181 message2 := hec.messages[1] 182 if message2.Time != fmt.Sprintf("%f", float64(message2Time.UnixNano())/float64(time.Second)) || 183 message2.Host != hostname || 184 message2.Source != "" || 185 message2.SourceType != "" || 186 message2.Index != "" { 187 t.Fatalf("Unexpected values of message 1 %v", message2) 188 } 189 190 if event, err := message2.EventAsMap(); err != nil { 191 t.Fatal(err) 192 } else { 193 if event["line"] != "notajson" || 194 event["source"] != "stdout" || 195 event["tag"] != "containeriid" || 196 len(event) != 3 { 197 t.Fatalf("Unexpected event in message %v", event) 198 } 199 } 200 201 err = hec.Close() 202 if err != nil { 203 t.Fatal(err) 204 } 205 } 206 207 // Verify inline format with a not default settings for most of options 208 func TestInlineFormatWithNonDefaultOptions(t *testing.T) { 209 hec := NewHTTPEventCollectorMock(t) 210 211 go hec.Serve() 212 213 info := logger.Info{ 214 Config: map[string]string{ 215 splunkURLKey: hec.URL(), 216 splunkTokenKey: hec.token, 217 splunkSourceKey: "mysource", 218 splunkSourceTypeKey: "mysourcetype", 219 splunkIndexKey: "myindex", 220 splunkFormatKey: splunkFormatInline, 221 splunkGzipCompressionKey: "true", 222 tagKey: "{{.ImageName}}/{{.Name}}", 223 labelsKey: "a", 224 envRegexKey: "^foo", 225 }, 226 ContainerID: "containeriid", 227 ContainerName: "/container_name", 228 ContainerImageID: "contaimageid", 229 ContainerImageName: "container_image_name", 230 ContainerLabels: map[string]string{ 231 "a": "b", 232 }, 233 ContainerEnv: []string{"foo_finder=bar"}, 234 } 235 236 hostname, err := info.Hostname() 237 if err != nil { 238 t.Fatal(err) 239 } 240 241 loggerDriver, err := New(info) 242 if err != nil { 243 t.Fatal(err) 244 } 245 246 if !hec.connectionVerified { 247 t.Fatal("By default connection should be verified") 248 } 249 250 splunkLoggerDriver, ok := loggerDriver.(*splunkLoggerInline) 251 if !ok { 252 t.Fatal("Unexpected Splunk Logging Driver type") 253 } 254 255 if splunkLoggerDriver.url != hec.URL()+"/services/collector/event/1.0" || 256 splunkLoggerDriver.auth != "Splunk "+hec.token || 257 splunkLoggerDriver.nullMessage.Host != hostname || 258 splunkLoggerDriver.nullMessage.Source != "mysource" || 259 splunkLoggerDriver.nullMessage.SourceType != "mysourcetype" || 260 splunkLoggerDriver.nullMessage.Index != "myindex" || 261 !splunkLoggerDriver.gzipCompression || 262 splunkLoggerDriver.gzipCompressionLevel != gzip.DefaultCompression || 263 splunkLoggerDriver.postMessagesFrequency != defaultPostMessagesFrequency || 264 splunkLoggerDriver.postMessagesBatchSize != defaultPostMessagesBatchSize || 265 splunkLoggerDriver.bufferMaximum != defaultBufferMaximum || 266 cap(splunkLoggerDriver.stream) != defaultStreamChannelSize { 267 t.Fatal("Values do not match configuration.") 268 } 269 270 messageTime := time.Now() 271 if err := loggerDriver.Log(&logger.Message{Line: []byte("1"), Source: "stdout", Timestamp: messageTime}); err != nil { 272 t.Fatal(err) 273 } 274 275 err = loggerDriver.Close() 276 if err != nil { 277 t.Fatal(err) 278 } 279 280 if len(hec.messages) != 1 { 281 t.Fatal("Expected one message") 282 } 283 284 if !*hec.gzipEnabled { 285 t.Fatal("Gzip should be used") 286 } 287 288 message := hec.messages[0] 289 if message.Time != fmt.Sprintf("%f", float64(messageTime.UnixNano())/float64(time.Second)) || 290 message.Host != hostname || 291 message.Source != "mysource" || 292 message.SourceType != "mysourcetype" || 293 message.Index != "myindex" { 294 t.Fatalf("Unexpected values of message %v", message) 295 } 296 297 if event, err := message.EventAsMap(); err != nil { 298 t.Fatal(err) 299 } else { 300 if event["line"] != "1" || 301 event["source"] != "stdout" || 302 event["tag"] != "container_image_name/container_name" || 303 event["attrs"].(map[string]interface{})["a"] != "b" || 304 event["attrs"].(map[string]interface{})["foo_finder"] != "bar" || 305 len(event) != 4 { 306 t.Fatalf("Unexpected event in message %v", event) 307 } 308 } 309 310 err = hec.Close() 311 if err != nil { 312 t.Fatal(err) 313 } 314 } 315 316 // Verify JSON format 317 func TestJsonFormat(t *testing.T) { 318 hec := NewHTTPEventCollectorMock(t) 319 320 go hec.Serve() 321 322 info := logger.Info{ 323 Config: map[string]string{ 324 splunkURLKey: hec.URL(), 325 splunkTokenKey: hec.token, 326 splunkFormatKey: splunkFormatJSON, 327 splunkGzipCompressionKey: "true", 328 splunkGzipCompressionLevelKey: "1", 329 }, 330 ContainerID: "containeriid", 331 ContainerName: "/container_name", 332 ContainerImageID: "contaimageid", 333 ContainerImageName: "container_image_name", 334 } 335 336 hostname, err := info.Hostname() 337 if err != nil { 338 t.Fatal(err) 339 } 340 341 loggerDriver, err := New(info) 342 if err != nil { 343 t.Fatal(err) 344 } 345 346 if !hec.connectionVerified { 347 t.Fatal("By default connection should be verified") 348 } 349 350 splunkLoggerDriver, ok := loggerDriver.(*splunkLoggerJSON) 351 if !ok { 352 t.Fatal("Unexpected Splunk Logging Driver type") 353 } 354 355 if splunkLoggerDriver.url != hec.URL()+"/services/collector/event/1.0" || 356 splunkLoggerDriver.auth != "Splunk "+hec.token || 357 splunkLoggerDriver.nullMessage.Host != hostname || 358 splunkLoggerDriver.nullMessage.Source != "" || 359 splunkLoggerDriver.nullMessage.SourceType != "" || 360 splunkLoggerDriver.nullMessage.Index != "" || 361 !splunkLoggerDriver.gzipCompression || 362 splunkLoggerDriver.gzipCompressionLevel != gzip.BestSpeed || 363 splunkLoggerDriver.postMessagesFrequency != defaultPostMessagesFrequency || 364 splunkLoggerDriver.postMessagesBatchSize != defaultPostMessagesBatchSize || 365 splunkLoggerDriver.bufferMaximum != defaultBufferMaximum || 366 cap(splunkLoggerDriver.stream) != defaultStreamChannelSize { 367 t.Fatal("Values do not match configuration.") 368 } 369 370 message1Time := time.Now() 371 if err := loggerDriver.Log(&logger.Message{Line: []byte("{\"a\":\"b\"}"), Source: "stdout", Timestamp: message1Time}); err != nil { 372 t.Fatal(err) 373 } 374 message2Time := time.Now() 375 if err := loggerDriver.Log(&logger.Message{Line: []byte("notjson"), Source: "stdout", Timestamp: message2Time}); err != nil { 376 t.Fatal(err) 377 } 378 379 err = loggerDriver.Close() 380 if err != nil { 381 t.Fatal(err) 382 } 383 384 if len(hec.messages) != 2 { 385 t.Fatal("Expected two messages") 386 } 387 388 message1 := hec.messages[0] 389 if message1.Time != fmt.Sprintf("%f", float64(message1Time.UnixNano())/float64(time.Second)) || 390 message1.Host != hostname || 391 message1.Source != "" || 392 message1.SourceType != "" || 393 message1.Index != "" { 394 t.Fatalf("Unexpected values of message 1 %v", message1) 395 } 396 397 if event, err := message1.EventAsMap(); err != nil { 398 t.Fatal(err) 399 } else { 400 if event["line"].(map[string]interface{})["a"] != "b" || 401 event["source"] != "stdout" || 402 event["tag"] != "containeriid" || 403 len(event) != 3 { 404 t.Fatalf("Unexpected event in message 1 %v", event) 405 } 406 } 407 408 message2 := hec.messages[1] 409 if message2.Time != fmt.Sprintf("%f", float64(message2Time.UnixNano())/float64(time.Second)) || 410 message2.Host != hostname || 411 message2.Source != "" || 412 message2.SourceType != "" || 413 message2.Index != "" { 414 t.Fatalf("Unexpected values of message 2 %v", message2) 415 } 416 417 // If message cannot be parsed as JSON - it should be sent as a line 418 if event, err := message2.EventAsMap(); err != nil { 419 t.Fatal(err) 420 } else { 421 if event["line"] != "notjson" || 422 event["source"] != "stdout" || 423 event["tag"] != "containeriid" || 424 len(event) != 3 { 425 t.Fatalf("Unexpected event in message 2 %v", event) 426 } 427 } 428 429 err = hec.Close() 430 if err != nil { 431 t.Fatal(err) 432 } 433 } 434 435 // Verify raw format 436 func TestRawFormat(t *testing.T) { 437 hec := NewHTTPEventCollectorMock(t) 438 439 go hec.Serve() 440 441 info := logger.Info{ 442 Config: map[string]string{ 443 splunkURLKey: hec.URL(), 444 splunkTokenKey: hec.token, 445 splunkFormatKey: splunkFormatRaw, 446 }, 447 ContainerID: "containeriid", 448 ContainerName: "/container_name", 449 ContainerImageID: "contaimageid", 450 ContainerImageName: "container_image_name", 451 } 452 453 hostname, err := info.Hostname() 454 require.NoError(t, err) 455 456 loggerDriver, err := New(info) 457 require.NoError(t, err) 458 459 if !hec.connectionVerified { 460 t.Fatal("By default connection should be verified") 461 } 462 463 splunkLoggerDriver, ok := loggerDriver.(*splunkLoggerRaw) 464 if !ok { 465 t.Fatal("Unexpected Splunk Logging Driver type") 466 } 467 468 if splunkLoggerDriver.url != hec.URL()+"/services/collector/event/1.0" || 469 splunkLoggerDriver.auth != "Splunk "+hec.token || 470 splunkLoggerDriver.nullMessage.Host != hostname || 471 splunkLoggerDriver.nullMessage.Source != "" || 472 splunkLoggerDriver.nullMessage.SourceType != "" || 473 splunkLoggerDriver.nullMessage.Index != "" || 474 splunkLoggerDriver.gzipCompression || 475 splunkLoggerDriver.postMessagesFrequency != defaultPostMessagesFrequency || 476 splunkLoggerDriver.postMessagesBatchSize != defaultPostMessagesBatchSize || 477 splunkLoggerDriver.bufferMaximum != defaultBufferMaximum || 478 cap(splunkLoggerDriver.stream) != defaultStreamChannelSize || 479 string(splunkLoggerDriver.prefix) != "containeriid " { 480 t.Fatal("Values do not match configuration.") 481 } 482 483 message1Time := time.Now() 484 if err := loggerDriver.Log(&logger.Message{Line: []byte("{\"a\":\"b\"}"), Source: "stdout", Timestamp: message1Time}); err != nil { 485 t.Fatal(err) 486 } 487 message2Time := time.Now() 488 if err := loggerDriver.Log(&logger.Message{Line: []byte("notjson"), Source: "stdout", Timestamp: message2Time}); err != nil { 489 t.Fatal(err) 490 } 491 492 err = loggerDriver.Close() 493 if err != nil { 494 t.Fatal(err) 495 } 496 497 if len(hec.messages) != 2 { 498 t.Fatal("Expected two messages") 499 } 500 501 message1 := hec.messages[0] 502 if message1.Time != fmt.Sprintf("%f", float64(message1Time.UnixNano())/float64(time.Second)) || 503 message1.Host != hostname || 504 message1.Source != "" || 505 message1.SourceType != "" || 506 message1.Index != "" { 507 t.Fatalf("Unexpected values of message 1 %v", message1) 508 } 509 510 if event, err := message1.EventAsString(); err != nil { 511 t.Fatal(err) 512 } else { 513 if event != "containeriid {\"a\":\"b\"}" { 514 t.Fatalf("Unexpected event in message 1 %v", event) 515 } 516 } 517 518 message2 := hec.messages[1] 519 if message2.Time != fmt.Sprintf("%f", float64(message2Time.UnixNano())/float64(time.Second)) || 520 message2.Host != hostname || 521 message2.Source != "" || 522 message2.SourceType != "" || 523 message2.Index != "" { 524 t.Fatalf("Unexpected values of message 2 %v", message2) 525 } 526 527 if event, err := message2.EventAsString(); err != nil { 528 t.Fatal(err) 529 } else { 530 if event != "containeriid notjson" { 531 t.Fatalf("Unexpected event in message 1 %v", event) 532 } 533 } 534 535 err = hec.Close() 536 if err != nil { 537 t.Fatal(err) 538 } 539 } 540 541 // Verify raw format with labels 542 func TestRawFormatWithLabels(t *testing.T) { 543 hec := NewHTTPEventCollectorMock(t) 544 545 go hec.Serve() 546 547 info := logger.Info{ 548 Config: map[string]string{ 549 splunkURLKey: hec.URL(), 550 splunkTokenKey: hec.token, 551 splunkFormatKey: splunkFormatRaw, 552 labelsKey: "a", 553 }, 554 ContainerID: "containeriid", 555 ContainerName: "/container_name", 556 ContainerImageID: "contaimageid", 557 ContainerImageName: "container_image_name", 558 ContainerLabels: map[string]string{ 559 "a": "b", 560 }, 561 } 562 563 hostname, err := info.Hostname() 564 if err != nil { 565 t.Fatal(err) 566 } 567 568 loggerDriver, err := New(info) 569 if err != nil { 570 t.Fatal(err) 571 } 572 573 if !hec.connectionVerified { 574 t.Fatal("By default connection should be verified") 575 } 576 577 splunkLoggerDriver, ok := loggerDriver.(*splunkLoggerRaw) 578 if !ok { 579 t.Fatal("Unexpected Splunk Logging Driver type") 580 } 581 582 if splunkLoggerDriver.url != hec.URL()+"/services/collector/event/1.0" || 583 splunkLoggerDriver.auth != "Splunk "+hec.token || 584 splunkLoggerDriver.nullMessage.Host != hostname || 585 splunkLoggerDriver.nullMessage.Source != "" || 586 splunkLoggerDriver.nullMessage.SourceType != "" || 587 splunkLoggerDriver.nullMessage.Index != "" || 588 splunkLoggerDriver.gzipCompression || 589 splunkLoggerDriver.postMessagesFrequency != defaultPostMessagesFrequency || 590 splunkLoggerDriver.postMessagesBatchSize != defaultPostMessagesBatchSize || 591 splunkLoggerDriver.bufferMaximum != defaultBufferMaximum || 592 cap(splunkLoggerDriver.stream) != defaultStreamChannelSize || 593 string(splunkLoggerDriver.prefix) != "containeriid a=b " { 594 t.Fatal("Values do not match configuration.") 595 } 596 597 message1Time := time.Now() 598 if err := loggerDriver.Log(&logger.Message{Line: []byte("{\"a\":\"b\"}"), Source: "stdout", Timestamp: message1Time}); err != nil { 599 t.Fatal(err) 600 } 601 message2Time := time.Now() 602 if err := loggerDriver.Log(&logger.Message{Line: []byte("notjson"), Source: "stdout", Timestamp: message2Time}); err != nil { 603 t.Fatal(err) 604 } 605 606 err = loggerDriver.Close() 607 if err != nil { 608 t.Fatal(err) 609 } 610 611 if len(hec.messages) != 2 { 612 t.Fatal("Expected two messages") 613 } 614 615 message1 := hec.messages[0] 616 if message1.Time != fmt.Sprintf("%f", float64(message1Time.UnixNano())/float64(time.Second)) || 617 message1.Host != hostname || 618 message1.Source != "" || 619 message1.SourceType != "" || 620 message1.Index != "" { 621 t.Fatalf("Unexpected values of message 1 %v", message1) 622 } 623 624 if event, err := message1.EventAsString(); err != nil { 625 t.Fatal(err) 626 } else { 627 if event != "containeriid a=b {\"a\":\"b\"}" { 628 t.Fatalf("Unexpected event in message 1 %v", event) 629 } 630 } 631 632 message2 := hec.messages[1] 633 if message2.Time != fmt.Sprintf("%f", float64(message2Time.UnixNano())/float64(time.Second)) || 634 message2.Host != hostname || 635 message2.Source != "" || 636 message2.SourceType != "" || 637 message2.Index != "" { 638 t.Fatalf("Unexpected values of message 2 %v", message2) 639 } 640 641 if event, err := message2.EventAsString(); err != nil { 642 t.Fatal(err) 643 } else { 644 if event != "containeriid a=b notjson" { 645 t.Fatalf("Unexpected event in message 2 %v", event) 646 } 647 } 648 649 err = hec.Close() 650 if err != nil { 651 t.Fatal(err) 652 } 653 } 654 655 // Verify that Splunk Logging Driver can accept tag="" which will allow to send raw messages 656 // in the same way we get them in stdout/stderr 657 func TestRawFormatWithoutTag(t *testing.T) { 658 hec := NewHTTPEventCollectorMock(t) 659 660 go hec.Serve() 661 662 info := logger.Info{ 663 Config: map[string]string{ 664 splunkURLKey: hec.URL(), 665 splunkTokenKey: hec.token, 666 splunkFormatKey: splunkFormatRaw, 667 tagKey: "", 668 }, 669 ContainerID: "containeriid", 670 ContainerName: "/container_name", 671 ContainerImageID: "contaimageid", 672 ContainerImageName: "container_image_name", 673 } 674 675 hostname, err := info.Hostname() 676 if err != nil { 677 t.Fatal(err) 678 } 679 680 loggerDriver, err := New(info) 681 if err != nil { 682 t.Fatal(err) 683 } 684 685 if !hec.connectionVerified { 686 t.Fatal("By default connection should be verified") 687 } 688 689 splunkLoggerDriver, ok := loggerDriver.(*splunkLoggerRaw) 690 if !ok { 691 t.Fatal("Unexpected Splunk Logging Driver type") 692 } 693 694 if splunkLoggerDriver.url != hec.URL()+"/services/collector/event/1.0" || 695 splunkLoggerDriver.auth != "Splunk "+hec.token || 696 splunkLoggerDriver.nullMessage.Host != hostname || 697 splunkLoggerDriver.nullMessage.Source != "" || 698 splunkLoggerDriver.nullMessage.SourceType != "" || 699 splunkLoggerDriver.nullMessage.Index != "" || 700 splunkLoggerDriver.gzipCompression || 701 splunkLoggerDriver.postMessagesFrequency != defaultPostMessagesFrequency || 702 splunkLoggerDriver.postMessagesBatchSize != defaultPostMessagesBatchSize || 703 splunkLoggerDriver.bufferMaximum != defaultBufferMaximum || 704 cap(splunkLoggerDriver.stream) != defaultStreamChannelSize || 705 string(splunkLoggerDriver.prefix) != "" { 706 t.Log(string(splunkLoggerDriver.prefix) + "a") 707 t.Fatal("Values do not match configuration.") 708 } 709 710 message1Time := time.Now() 711 if err := loggerDriver.Log(&logger.Message{Line: []byte("{\"a\":\"b\"}"), Source: "stdout", Timestamp: message1Time}); err != nil { 712 t.Fatal(err) 713 } 714 message2Time := time.Now() 715 if err := loggerDriver.Log(&logger.Message{Line: []byte("notjson"), Source: "stdout", Timestamp: message2Time}); err != nil { 716 t.Fatal(err) 717 } 718 message3Time := time.Now() 719 if err := loggerDriver.Log(&logger.Message{Line: []byte(" "), Source: "stdout", Timestamp: message3Time}); err != nil { 720 t.Fatal(err) 721 } 722 723 err = loggerDriver.Close() 724 if err != nil { 725 t.Fatal(err) 726 } 727 728 // message3 would have an empty or whitespace only string in the "event" field 729 // both of which are not acceptable to HEC 730 // thus here we must expect 2 messages, not 3 731 if len(hec.messages) != 2 { 732 t.Fatal("Expected two messages") 733 } 734 735 message1 := hec.messages[0] 736 if message1.Time != fmt.Sprintf("%f", float64(message1Time.UnixNano())/float64(time.Second)) || 737 message1.Host != hostname || 738 message1.Source != "" || 739 message1.SourceType != "" || 740 message1.Index != "" { 741 t.Fatalf("Unexpected values of message 1 %v", message1) 742 } 743 744 if event, err := message1.EventAsString(); err != nil { 745 t.Fatal(err) 746 } else { 747 if event != "{\"a\":\"b\"}" { 748 t.Fatalf("Unexpected event in message 1 %v", event) 749 } 750 } 751 752 message2 := hec.messages[1] 753 if message2.Time != fmt.Sprintf("%f", float64(message2Time.UnixNano())/float64(time.Second)) || 754 message2.Host != hostname || 755 message2.Source != "" || 756 message2.SourceType != "" || 757 message2.Index != "" { 758 t.Fatalf("Unexpected values of message 2 %v", message2) 759 } 760 761 if event, err := message2.EventAsString(); err != nil { 762 t.Fatal(err) 763 } else { 764 if event != "notjson" { 765 t.Fatalf("Unexpected event in message 2 %v", event) 766 } 767 } 768 769 err = hec.Close() 770 if err != nil { 771 t.Fatal(err) 772 } 773 } 774 775 // Verify that we will send messages in batches with default batching parameters, 776 // but change frequency to be sure that numOfRequests will match expected 17 requests 777 func TestBatching(t *testing.T) { 778 if err := os.Setenv(envVarPostMessagesFrequency, "10h"); err != nil { 779 t.Fatal(err) 780 } 781 782 hec := NewHTTPEventCollectorMock(t) 783 784 go hec.Serve() 785 786 info := logger.Info{ 787 Config: map[string]string{ 788 splunkURLKey: hec.URL(), 789 splunkTokenKey: hec.token, 790 }, 791 ContainerID: "containeriid", 792 ContainerName: "/container_name", 793 ContainerImageID: "contaimageid", 794 ContainerImageName: "container_image_name", 795 } 796 797 loggerDriver, err := New(info) 798 if err != nil { 799 t.Fatal(err) 800 } 801 802 for i := 0; i < defaultStreamChannelSize*4; i++ { 803 if err := loggerDriver.Log(&logger.Message{Line: []byte(fmt.Sprintf("%d", i)), Source: "stdout", Timestamp: time.Now()}); err != nil { 804 t.Fatal(err) 805 } 806 } 807 808 err = loggerDriver.Close() 809 if err != nil { 810 t.Fatal(err) 811 } 812 813 if len(hec.messages) != defaultStreamChannelSize*4 { 814 t.Fatal("Not all messages delivered") 815 } 816 817 for i, message := range hec.messages { 818 if event, err := message.EventAsMap(); err != nil { 819 t.Fatal(err) 820 } else { 821 if event["line"] != fmt.Sprintf("%d", i) { 822 t.Fatalf("Unexpected event in message %v", event) 823 } 824 } 825 } 826 827 // 1 to verify connection and 16 batches 828 if hec.numOfRequests != 17 { 829 t.Fatalf("Unexpected number of requests %d", hec.numOfRequests) 830 } 831 832 err = hec.Close() 833 if err != nil { 834 t.Fatal(err) 835 } 836 837 if err := os.Setenv(envVarPostMessagesFrequency, ""); err != nil { 838 t.Fatal(err) 839 } 840 } 841 842 // Verify that test is using time to fire events not rare than specified frequency 843 func TestFrequency(t *testing.T) { 844 if err := os.Setenv(envVarPostMessagesFrequency, "5ms"); err != nil { 845 t.Fatal(err) 846 } 847 848 hec := NewHTTPEventCollectorMock(t) 849 850 go hec.Serve() 851 852 info := logger.Info{ 853 Config: map[string]string{ 854 splunkURLKey: hec.URL(), 855 splunkTokenKey: hec.token, 856 }, 857 ContainerID: "containeriid", 858 ContainerName: "/container_name", 859 ContainerImageID: "contaimageid", 860 ContainerImageName: "container_image_name", 861 } 862 863 loggerDriver, err := New(info) 864 if err != nil { 865 t.Fatal(err) 866 } 867 868 for i := 0; i < 10; i++ { 869 if err := loggerDriver.Log(&logger.Message{Line: []byte(fmt.Sprintf("%d", i)), Source: "stdout", Timestamp: time.Now()}); err != nil { 870 t.Fatal(err) 871 } 872 time.Sleep(15 * time.Millisecond) 873 } 874 875 err = loggerDriver.Close() 876 if err != nil { 877 t.Fatal(err) 878 } 879 880 if len(hec.messages) != 10 { 881 t.Fatal("Not all messages delivered") 882 } 883 884 for i, message := range hec.messages { 885 if event, err := message.EventAsMap(); err != nil { 886 t.Fatal(err) 887 } else { 888 if event["line"] != fmt.Sprintf("%d", i) { 889 t.Fatalf("Unexpected event in message %v", event) 890 } 891 } 892 } 893 894 // 1 to verify connection and 10 to verify that we have sent messages with required frequency, 895 // but because frequency is too small (to keep test quick), instead of 11, use 9 if context switches will be slow 896 if hec.numOfRequests < 9 { 897 t.Fatalf("Unexpected number of requests %d", hec.numOfRequests) 898 } 899 900 err = hec.Close() 901 if err != nil { 902 t.Fatal(err) 903 } 904 905 if err := os.Setenv(envVarPostMessagesFrequency, ""); err != nil { 906 t.Fatal(err) 907 } 908 } 909 910 // Simulate behavior similar to first version of Splunk Logging Driver, when we were sending one message 911 // per request 912 func TestOneMessagePerRequest(t *testing.T) { 913 if err := os.Setenv(envVarPostMessagesFrequency, "10h"); err != nil { 914 t.Fatal(err) 915 } 916 917 if err := os.Setenv(envVarPostMessagesBatchSize, "1"); err != nil { 918 t.Fatal(err) 919 } 920 921 if err := os.Setenv(envVarBufferMaximum, "1"); err != nil { 922 t.Fatal(err) 923 } 924 925 if err := os.Setenv(envVarStreamChannelSize, "0"); err != nil { 926 t.Fatal(err) 927 } 928 929 hec := NewHTTPEventCollectorMock(t) 930 931 go hec.Serve() 932 933 info := logger.Info{ 934 Config: map[string]string{ 935 splunkURLKey: hec.URL(), 936 splunkTokenKey: hec.token, 937 }, 938 ContainerID: "containeriid", 939 ContainerName: "/container_name", 940 ContainerImageID: "contaimageid", 941 ContainerImageName: "container_image_name", 942 } 943 944 loggerDriver, err := New(info) 945 if err != nil { 946 t.Fatal(err) 947 } 948 949 for i := 0; i < 10; i++ { 950 if err := loggerDriver.Log(&logger.Message{Line: []byte(fmt.Sprintf("%d", i)), Source: "stdout", Timestamp: time.Now()}); err != nil { 951 t.Fatal(err) 952 } 953 } 954 955 err = loggerDriver.Close() 956 if err != nil { 957 t.Fatal(err) 958 } 959 960 if len(hec.messages) != 10 { 961 t.Fatal("Not all messages delivered") 962 } 963 964 for i, message := range hec.messages { 965 if event, err := message.EventAsMap(); err != nil { 966 t.Fatal(err) 967 } else { 968 if event["line"] != fmt.Sprintf("%d", i) { 969 t.Fatalf("Unexpected event in message %v", event) 970 } 971 } 972 } 973 974 // 1 to verify connection and 10 messages 975 if hec.numOfRequests != 11 { 976 t.Fatalf("Unexpected number of requests %d", hec.numOfRequests) 977 } 978 979 err = hec.Close() 980 if err != nil { 981 t.Fatal(err) 982 } 983 984 if err := os.Setenv(envVarPostMessagesFrequency, ""); err != nil { 985 t.Fatal(err) 986 } 987 988 if err := os.Setenv(envVarPostMessagesBatchSize, ""); err != nil { 989 t.Fatal(err) 990 } 991 992 if err := os.Setenv(envVarBufferMaximum, ""); err != nil { 993 t.Fatal(err) 994 } 995 996 if err := os.Setenv(envVarStreamChannelSize, ""); err != nil { 997 t.Fatal(err) 998 } 999 } 1000 1001 // Driver should not be created when HEC is unresponsive 1002 func TestVerify(t *testing.T) { 1003 hec := NewHTTPEventCollectorMock(t) 1004 hec.simulateServerError = true 1005 go hec.Serve() 1006 1007 info := logger.Info{ 1008 Config: map[string]string{ 1009 splunkURLKey: hec.URL(), 1010 splunkTokenKey: hec.token, 1011 }, 1012 ContainerID: "containeriid", 1013 ContainerName: "/container_name", 1014 ContainerImageID: "contaimageid", 1015 ContainerImageName: "container_image_name", 1016 } 1017 1018 _, err := New(info) 1019 if err == nil { 1020 t.Fatal("Expecting driver to fail, when server is unresponsive") 1021 } 1022 1023 err = hec.Close() 1024 if err != nil { 1025 t.Fatal(err) 1026 } 1027 } 1028 1029 // Verify that user can specify to skip verification that Splunk HEC is working. 1030 // Also in this test we verify retry logic. 1031 func TestSkipVerify(t *testing.T) { 1032 hec := NewHTTPEventCollectorMock(t) 1033 hec.simulateServerError = true 1034 go hec.Serve() 1035 1036 info := logger.Info{ 1037 Config: map[string]string{ 1038 splunkURLKey: hec.URL(), 1039 splunkTokenKey: hec.token, 1040 splunkVerifyConnectionKey: "false", 1041 }, 1042 ContainerID: "containeriid", 1043 ContainerName: "/container_name", 1044 ContainerImageID: "contaimageid", 1045 ContainerImageName: "container_image_name", 1046 } 1047 1048 loggerDriver, err := New(info) 1049 if err != nil { 1050 t.Fatal(err) 1051 } 1052 1053 if hec.connectionVerified { 1054 t.Fatal("Connection should not be verified") 1055 } 1056 1057 for i := 0; i < defaultStreamChannelSize*2; i++ { 1058 if err := loggerDriver.Log(&logger.Message{Line: []byte(fmt.Sprintf("%d", i)), Source: "stdout", Timestamp: time.Now()}); err != nil { 1059 t.Fatal(err) 1060 } 1061 } 1062 1063 if len(hec.messages) != 0 { 1064 t.Fatal("No messages should be accepted at this point") 1065 } 1066 1067 hec.simulateErr(false) 1068 1069 for i := defaultStreamChannelSize * 2; i < defaultStreamChannelSize*4; i++ { 1070 if err := loggerDriver.Log(&logger.Message{Line: []byte(fmt.Sprintf("%d", i)), Source: "stdout", Timestamp: time.Now()}); err != nil { 1071 t.Fatal(err) 1072 } 1073 } 1074 1075 err = loggerDriver.Close() 1076 if err != nil { 1077 t.Fatal(err) 1078 } 1079 1080 if len(hec.messages) != defaultStreamChannelSize*4 { 1081 t.Fatal("Not all messages delivered") 1082 } 1083 1084 for i, message := range hec.messages { 1085 if event, err := message.EventAsMap(); err != nil { 1086 t.Fatal(err) 1087 } else { 1088 if event["line"] != fmt.Sprintf("%d", i) { 1089 t.Fatalf("Unexpected event in message %v", event) 1090 } 1091 } 1092 } 1093 1094 err = hec.Close() 1095 if err != nil { 1096 t.Fatal(err) 1097 } 1098 } 1099 1100 // Verify logic for when we filled whole buffer 1101 func TestBufferMaximum(t *testing.T) { 1102 if err := os.Setenv(envVarPostMessagesBatchSize, "2"); err != nil { 1103 t.Fatal(err) 1104 } 1105 1106 if err := os.Setenv(envVarBufferMaximum, "10"); err != nil { 1107 t.Fatal(err) 1108 } 1109 1110 if err := os.Setenv(envVarStreamChannelSize, "0"); err != nil { 1111 t.Fatal(err) 1112 } 1113 1114 hec := NewHTTPEventCollectorMock(t) 1115 hec.simulateErr(true) 1116 go hec.Serve() 1117 1118 info := logger.Info{ 1119 Config: map[string]string{ 1120 splunkURLKey: hec.URL(), 1121 splunkTokenKey: hec.token, 1122 splunkVerifyConnectionKey: "false", 1123 }, 1124 ContainerID: "containeriid", 1125 ContainerName: "/container_name", 1126 ContainerImageID: "contaimageid", 1127 ContainerImageName: "container_image_name", 1128 } 1129 1130 loggerDriver, err := New(info) 1131 if err != nil { 1132 t.Fatal(err) 1133 } 1134 1135 if hec.connectionVerified { 1136 t.Fatal("Connection should not be verified") 1137 } 1138 1139 for i := 0; i < 11; i++ { 1140 if err := loggerDriver.Log(&logger.Message{Line: []byte(fmt.Sprintf("%d", i)), Source: "stdout", Timestamp: time.Now()}); err != nil { 1141 t.Fatal(err) 1142 } 1143 } 1144 1145 if len(hec.messages) != 0 { 1146 t.Fatal("No messages should be accepted at this point") 1147 } 1148 1149 hec.simulateServerError = false 1150 1151 err = loggerDriver.Close() 1152 if err != nil { 1153 t.Fatal(err) 1154 } 1155 1156 if len(hec.messages) != 9 { 1157 t.Fatalf("Expected # of messages %d, got %d", 9, len(hec.messages)) 1158 } 1159 1160 // First 1000 messages are written to daemon log when buffer was full 1161 for i, message := range hec.messages { 1162 if event, err := message.EventAsMap(); err != nil { 1163 t.Fatal(err) 1164 } else { 1165 if event["line"] != fmt.Sprintf("%d", i+2) { 1166 t.Fatalf("Unexpected event in message %v", event) 1167 } 1168 } 1169 } 1170 1171 err = hec.Close() 1172 if err != nil { 1173 t.Fatal(err) 1174 } 1175 1176 if err := os.Setenv(envVarPostMessagesBatchSize, ""); err != nil { 1177 t.Fatal(err) 1178 } 1179 1180 if err := os.Setenv(envVarBufferMaximum, ""); err != nil { 1181 t.Fatal(err) 1182 } 1183 1184 if err := os.Setenv(envVarStreamChannelSize, ""); err != nil { 1185 t.Fatal(err) 1186 } 1187 } 1188 1189 // Verify that we are not blocking close when HEC is down for the whole time 1190 func TestServerAlwaysDown(t *testing.T) { 1191 if err := os.Setenv(envVarPostMessagesBatchSize, "2"); err != nil { 1192 t.Fatal(err) 1193 } 1194 1195 if err := os.Setenv(envVarBufferMaximum, "4"); err != nil { 1196 t.Fatal(err) 1197 } 1198 1199 if err := os.Setenv(envVarStreamChannelSize, "0"); err != nil { 1200 t.Fatal(err) 1201 } 1202 1203 hec := NewHTTPEventCollectorMock(t) 1204 hec.simulateServerError = true 1205 go hec.Serve() 1206 1207 info := logger.Info{ 1208 Config: map[string]string{ 1209 splunkURLKey: hec.URL(), 1210 splunkTokenKey: hec.token, 1211 splunkVerifyConnectionKey: "false", 1212 }, 1213 ContainerID: "containeriid", 1214 ContainerName: "/container_name", 1215 ContainerImageID: "contaimageid", 1216 ContainerImageName: "container_image_name", 1217 } 1218 1219 loggerDriver, err := New(info) 1220 if err != nil { 1221 t.Fatal(err) 1222 } 1223 1224 if hec.connectionVerified { 1225 t.Fatal("Connection should not be verified") 1226 } 1227 1228 for i := 0; i < 5; i++ { 1229 if err := loggerDriver.Log(&logger.Message{Line: []byte(fmt.Sprintf("%d", i)), Source: "stdout", Timestamp: time.Now()}); err != nil { 1230 t.Fatal(err) 1231 } 1232 } 1233 1234 err = loggerDriver.Close() 1235 if err != nil { 1236 t.Fatal(err) 1237 } 1238 1239 if len(hec.messages) != 0 { 1240 t.Fatal("No messages should be sent") 1241 } 1242 1243 err = hec.Close() 1244 if err != nil { 1245 t.Fatal(err) 1246 } 1247 1248 if err := os.Setenv(envVarPostMessagesBatchSize, ""); err != nil { 1249 t.Fatal(err) 1250 } 1251 1252 if err := os.Setenv(envVarBufferMaximum, ""); err != nil { 1253 t.Fatal(err) 1254 } 1255 1256 if err := os.Setenv(envVarStreamChannelSize, ""); err != nil { 1257 t.Fatal(err) 1258 } 1259 } 1260 1261 // Cannot send messages after we close driver 1262 func TestCannotSendAfterClose(t *testing.T) { 1263 hec := NewHTTPEventCollectorMock(t) 1264 go hec.Serve() 1265 1266 info := logger.Info{ 1267 Config: map[string]string{ 1268 splunkURLKey: hec.URL(), 1269 splunkTokenKey: hec.token, 1270 }, 1271 ContainerID: "containeriid", 1272 ContainerName: "/container_name", 1273 ContainerImageID: "contaimageid", 1274 ContainerImageName: "container_image_name", 1275 } 1276 1277 loggerDriver, err := New(info) 1278 if err != nil { 1279 t.Fatal(err) 1280 } 1281 1282 if err := loggerDriver.Log(&logger.Message{Line: []byte("message1"), Source: "stdout", Timestamp: time.Now()}); err != nil { 1283 t.Fatal(err) 1284 } 1285 1286 err = loggerDriver.Close() 1287 if err != nil { 1288 t.Fatal(err) 1289 } 1290 1291 if err := loggerDriver.Log(&logger.Message{Line: []byte("message2"), Source: "stdout", Timestamp: time.Now()}); err == nil { 1292 t.Fatal("Driver should not allow to send messages after close") 1293 } 1294 1295 if len(hec.messages) != 1 { 1296 t.Fatal("Only one message should be sent") 1297 } 1298 1299 message := hec.messages[0] 1300 if event, err := message.EventAsMap(); err != nil { 1301 t.Fatal(err) 1302 } else { 1303 if event["line"] != "message1" { 1304 t.Fatalf("Unexpected event in message %v", event) 1305 } 1306 } 1307 1308 err = hec.Close() 1309 if err != nil { 1310 t.Fatal(err) 1311 } 1312 } 1313 1314 func TestDeadlockOnBlockedEndpoint(t *testing.T) { 1315 hec := NewHTTPEventCollectorMock(t) 1316 go hec.Serve() 1317 info := logger.Info{ 1318 Config: map[string]string{ 1319 splunkURLKey: hec.URL(), 1320 splunkTokenKey: hec.token, 1321 }, 1322 ContainerID: "containeriid", 1323 ContainerName: "/container_name", 1324 ContainerImageID: "contaimageid", 1325 ContainerImageName: "container_image_name", 1326 } 1327 1328 l, err := New(info) 1329 if err != nil { 1330 t.Fatal(err) 1331 } 1332 1333 ctx, unblock := context.WithCancel(context.Background()) 1334 hec.withBlock(ctx) 1335 defer unblock() 1336 1337 batchSendTimeout = 1 * time.Second 1338 1339 if err := l.Log(&logger.Message{}); err != nil { 1340 t.Fatal(err) 1341 } 1342 1343 done := make(chan struct{}) 1344 go func() { 1345 l.Close() 1346 close(done) 1347 }() 1348 1349 select { 1350 case <-time.After(60 * time.Second): 1351 buf := make([]byte, 1e6) 1352 buf = buf[:runtime.Stack(buf, true)] 1353 t.Logf("STACK DUMP: \n\n%s\n\n", string(buf)) 1354 t.Fatal("timeout waiting for close to finish") 1355 case <-done: 1356 } 1357 }