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