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