github.com/influxdata/telegraf@v1.30.3/config/config_test.go (about) 1 package config_test 2 3 import ( 4 "bytes" 5 "fmt" 6 "net/http" 7 "net/http/httptest" 8 "os" 9 "os/exec" 10 "path/filepath" 11 "reflect" 12 "regexp" 13 "runtime" 14 "strings" 15 "sync" 16 "testing" 17 "time" 18 19 "github.com/google/go-cmp/cmp" 20 "github.com/google/go-cmp/cmp/cmpopts" 21 "github.com/stretchr/testify/require" 22 23 "github.com/influxdata/telegraf" 24 "github.com/influxdata/telegraf/config" 25 "github.com/influxdata/telegraf/metric" 26 "github.com/influxdata/telegraf/models" 27 "github.com/influxdata/telegraf/persister" 28 "github.com/influxdata/telegraf/plugins/common/tls" 29 "github.com/influxdata/telegraf/plugins/inputs" 30 "github.com/influxdata/telegraf/plugins/outputs" 31 "github.com/influxdata/telegraf/plugins/parsers" 32 _ "github.com/influxdata/telegraf/plugins/parsers/all" // Blank import to have all parsers for testing 33 "github.com/influxdata/telegraf/plugins/parsers/json" 34 "github.com/influxdata/telegraf/plugins/processors" 35 "github.com/influxdata/telegraf/plugins/serializers" 36 _ "github.com/influxdata/telegraf/plugins/serializers/all" // Blank import to have all serializers for testing 37 promserializer "github.com/influxdata/telegraf/plugins/serializers/prometheus" 38 "github.com/influxdata/telegraf/testutil" 39 ) 40 41 func TestReadBinaryFile(t *testing.T) { 42 // Create a temporary binary file using the Telegraf tool custom_builder to pass as a config 43 wd, err := os.Getwd() 44 require.NoError(t, err) 45 t.Cleanup(func() { 46 err := os.Chdir(wd) 47 require.NoError(t, err) 48 }) 49 50 err = os.Chdir("../") 51 require.NoError(t, err) 52 tmpdir := t.TempDir() 53 binaryFile := filepath.Join(tmpdir, "custom_builder") 54 cmd := exec.Command("go", "build", "-o", binaryFile, "./tools/custom_builder") 55 var outb, errb bytes.Buffer 56 cmd.Stdout = &outb 57 cmd.Stderr = &errb 58 err = cmd.Run() 59 60 require.NoError(t, err, fmt.Sprintf("stdout: %s, stderr: %s", outb.String(), errb.String())) 61 c := config.NewConfig() 62 err = c.LoadConfig(binaryFile) 63 require.Error(t, err) 64 require.ErrorContains(t, err, "provided config is not a TOML file") 65 } 66 67 func TestConfig_LoadSingleInputWithEnvVars(t *testing.T) { 68 c := config.NewConfig() 69 t.Setenv("MY_TEST_SERVER", "192.168.1.1") 70 t.Setenv("TEST_INTERVAL", "10s") 71 require.NoError(t, c.LoadConfig("./testdata/single_plugin_env_vars.toml")) 72 73 input := inputs.Inputs["memcached"]().(*MockupInputPlugin) 74 input.Servers = []string{"192.168.1.1"} 75 input.Command = `Raw command which may or may not contain # in it 76 # is unique` 77 78 filter := models.Filter{ 79 NameDrop: []string{"metricname2"}, 80 NamePass: []string{"metricname1", "ip_192.168.1.1_name"}, 81 FieldExclude: []string{"other", "stuff"}, 82 FieldInclude: []string{"some", "strings"}, 83 TagDropFilters: []models.TagFilter{ 84 { 85 Name: "badtag", 86 Values: []string{"othertag"}, 87 }, 88 }, 89 TagPassFilters: []models.TagFilter{ 90 { 91 Name: "goodtag", 92 Values: []string{"mytag", "tagwith#value", "TagWithMultilineSyntax"}, 93 }, 94 }, 95 } 96 require.NoError(t, filter.Compile()) 97 inputConfig := &models.InputConfig{ 98 Name: "memcached", 99 Filter: filter, 100 Interval: 10 * time.Second, 101 } 102 inputConfig.Tags = make(map[string]string) 103 104 // Ignore Log, Parser and ID 105 c.Inputs[0].Input.(*MockupInputPlugin).Log = nil 106 c.Inputs[0].Input.(*MockupInputPlugin).parser = nil 107 c.Inputs[0].Config.ID = "" 108 require.Equal(t, input, c.Inputs[0].Input, "Testdata did not produce a correct mockup struct.") 109 require.Equal(t, inputConfig, c.Inputs[0].Config, "Testdata did not produce correct input metadata.") 110 } 111 112 func TestConfig_LoadSingleInput(t *testing.T) { 113 c := config.NewConfig() 114 require.NoError(t, c.LoadConfig("./testdata/single_plugin.toml")) 115 116 input := inputs.Inputs["memcached"]().(*MockupInputPlugin) 117 input.Servers = []string{"localhost"} 118 119 filter := models.Filter{ 120 NameDrop: []string{"metricname2"}, 121 NamePass: []string{"metricname1"}, 122 FieldExclude: []string{"other", "stuff"}, 123 FieldInclude: []string{"some", "strings"}, 124 TagDropFilters: []models.TagFilter{ 125 { 126 Name: "badtag", 127 Values: []string{"othertag"}, 128 }, 129 }, 130 TagPassFilters: []models.TagFilter{ 131 { 132 Name: "goodtag", 133 Values: []string{"mytag"}, 134 }, 135 }, 136 } 137 require.NoError(t, filter.Compile()) 138 inputConfig := &models.InputConfig{ 139 Name: "memcached", 140 Filter: filter, 141 Interval: 5 * time.Second, 142 } 143 inputConfig.Tags = make(map[string]string) 144 145 // Ignore Log, Parser and ID 146 c.Inputs[0].Input.(*MockupInputPlugin).Log = nil 147 c.Inputs[0].Input.(*MockupInputPlugin).parser = nil 148 c.Inputs[0].Config.ID = "" 149 require.Equal(t, input, c.Inputs[0].Input, "Testdata did not produce a correct memcached struct.") 150 require.Equal(t, inputConfig, c.Inputs[0].Config, "Testdata did not produce correct memcached metadata.") 151 } 152 153 func TestConfig_LoadSingleInput_WithSeparators(t *testing.T) { 154 c := config.NewConfig() 155 require.NoError(t, c.LoadConfig("./testdata/single_plugin_with_separators.toml")) 156 157 input := inputs.Inputs["memcached"]().(*MockupInputPlugin) 158 input.Servers = []string{"localhost"} 159 160 filter := models.Filter{ 161 NameDrop: []string{"metricname2"}, 162 NameDropSeparators: ".", 163 NamePass: []string{"metricname1"}, 164 NamePassSeparators: ".", 165 FieldExclude: []string{"other", "stuff"}, 166 FieldInclude: []string{"some", "strings"}, 167 TagDropFilters: []models.TagFilter{ 168 { 169 Name: "badtag", 170 Values: []string{"othertag"}, 171 }, 172 }, 173 TagPassFilters: []models.TagFilter{ 174 { 175 Name: "goodtag", 176 Values: []string{"mytag"}, 177 }, 178 }, 179 } 180 require.NoError(t, filter.Compile()) 181 inputConfig := &models.InputConfig{ 182 Name: "memcached", 183 Filter: filter, 184 Interval: 5 * time.Second, 185 } 186 inputConfig.Tags = make(map[string]string) 187 188 // Ignore Log, Parser and ID 189 c.Inputs[0].Input.(*MockupInputPlugin).Log = nil 190 c.Inputs[0].Input.(*MockupInputPlugin).parser = nil 191 c.Inputs[0].Config.ID = "" 192 require.Equal(t, input, c.Inputs[0].Input, "Testdata did not produce a correct memcached struct.") 193 require.Equal(t, inputConfig, c.Inputs[0].Config, "Testdata did not produce correct memcached metadata.") 194 } 195 196 func TestConfig_LoadSingleInput_WithCommentInArray(t *testing.T) { 197 c := config.NewConfig() 198 require.NoError(t, c.LoadConfig("./testdata/single_plugin_with_comment_in_array.toml")) 199 require.Len(t, c.Inputs, 1) 200 201 input := c.Inputs[0].Input.(*MockupInputPlugin) 202 require.ElementsMatch(t, input.Servers, []string{"localhost"}) 203 } 204 205 func TestConfig_LoadDirectory(t *testing.T) { 206 c := config.NewConfig() 207 208 files, err := config.WalkDirectory("./testdata/subconfig") 209 files = append([]string{"./testdata/single_plugin.toml"}, files...) 210 require.NoError(t, err) 211 require.NoError(t, c.LoadAll(files...)) 212 213 // Create the expected data 214 expectedPlugins := make([]*MockupInputPlugin, 4) 215 expectedConfigs := make([]*models.InputConfig, 4) 216 217 expectedPlugins[0] = inputs.Inputs["memcached"]().(*MockupInputPlugin) 218 expectedPlugins[0].Servers = []string{"localhost"} 219 220 filterMockup := models.Filter{ 221 NameDrop: []string{"metricname2"}, 222 NamePass: []string{"metricname1"}, 223 FieldExclude: []string{"other", "stuff"}, 224 FieldInclude: []string{"some", "strings"}, 225 TagDropFilters: []models.TagFilter{ 226 { 227 Name: "badtag", 228 Values: []string{"othertag"}, 229 }, 230 }, 231 TagPassFilters: []models.TagFilter{ 232 { 233 Name: "goodtag", 234 Values: []string{"mytag"}, 235 }, 236 }, 237 } 238 require.NoError(t, filterMockup.Compile()) 239 expectedConfigs[0] = &models.InputConfig{ 240 Name: "memcached", 241 Filter: filterMockup, 242 Interval: 5 * time.Second, 243 } 244 expectedConfigs[0].Tags = make(map[string]string) 245 246 expectedPlugins[1] = inputs.Inputs["exec"]().(*MockupInputPlugin) 247 parser := &json.Parser{ 248 MetricName: "exec", 249 Strict: true, 250 } 251 require.NoError(t, parser.Init()) 252 253 expectedPlugins[1].SetParser(parser) 254 expectedPlugins[1].Command = "/usr/bin/myothercollector --foo=bar" 255 expectedConfigs[1] = &models.InputConfig{ 256 Name: "exec", 257 MeasurementSuffix: "_myothercollector", 258 } 259 expectedConfigs[1].Tags = make(map[string]string) 260 261 expectedPlugins[2] = inputs.Inputs["memcached"]().(*MockupInputPlugin) 262 expectedPlugins[2].Servers = []string{"192.168.1.1"} 263 264 filterMemcached := models.Filter{ 265 NameDrop: []string{"metricname2"}, 266 NamePass: []string{"metricname1"}, 267 FieldExclude: []string{"other", "stuff"}, 268 FieldInclude: []string{"some", "strings"}, 269 TagDropFilters: []models.TagFilter{ 270 { 271 Name: "badtag", 272 Values: []string{"othertag"}, 273 }, 274 }, 275 TagPassFilters: []models.TagFilter{ 276 { 277 Name: "goodtag", 278 Values: []string{"mytag"}, 279 }, 280 }, 281 } 282 require.NoError(t, filterMemcached.Compile()) 283 expectedConfigs[2] = &models.InputConfig{ 284 Name: "memcached", 285 Filter: filterMemcached, 286 Interval: 5 * time.Second, 287 } 288 expectedConfigs[2].Tags = make(map[string]string) 289 290 expectedPlugins[3] = inputs.Inputs["procstat"]().(*MockupInputPlugin) 291 expectedPlugins[3].PidFile = "/var/run/grafana-server.pid" 292 expectedConfigs[3] = &models.InputConfig{Name: "procstat"} 293 expectedConfigs[3].Tags = make(map[string]string) 294 295 // Check the generated plugins 296 require.Len(t, c.Inputs, len(expectedPlugins)) 297 require.Len(t, c.Inputs, len(expectedConfigs)) 298 for i, plugin := range c.Inputs { 299 input := plugin.Input.(*MockupInputPlugin) 300 // Check the logger and ignore it for comparison 301 require.NotNil(t, input.Log) 302 input.Log = nil 303 304 // Check the parsers if any 305 if expectedPlugins[i].parser != nil { 306 runningParser, ok := input.parser.(*models.RunningParser) 307 require.True(t, ok) 308 309 // We only use the JSON parser here 310 parser, ok := runningParser.Parser.(*json.Parser) 311 require.True(t, ok) 312 313 // Prepare parser for comparison 314 require.NoError(t, parser.Init()) 315 parser.Log = nil 316 317 // Compare the parser 318 require.Equalf(t, expectedPlugins[i].parser, parser, "Plugin %d: incorrect parser produced", i) 319 } 320 321 // Ignore the parsers for further comparisons 322 input.parser = nil 323 expectedPlugins[i].parser = nil 324 325 // Ignore the ID 326 plugin.Config.ID = "" 327 328 require.Equalf(t, expectedPlugins[i], plugin.Input, "Plugin %d: incorrect struct produced", i) 329 require.Equalf(t, expectedConfigs[i], plugin.Config, "Plugin %d: incorrect config produced", i) 330 } 331 } 332 333 func TestConfig_WrongCertPath(t *testing.T) { 334 c := config.NewConfig() 335 require.Error(t, c.LoadConfig("./testdata/wrong_cert_path.toml")) 336 } 337 338 func TestConfig_DefaultParser(t *testing.T) { 339 c := config.NewConfig() 340 require.NoError(t, c.LoadConfig("./testdata/default_parser.toml")) 341 } 342 343 func TestConfig_DefaultExecParser(t *testing.T) { 344 c := config.NewConfig() 345 require.NoError(t, c.LoadConfig("./testdata/default_parser_exec.toml")) 346 } 347 348 func TestConfig_LoadSpecialTypes(t *testing.T) { 349 c := config.NewConfig() 350 require.NoError(t, c.LoadConfig("./testdata/special_types.toml")) 351 require.Len(t, c.Inputs, 1) 352 353 input, ok := c.Inputs[0].Input.(*MockupInputPlugin) 354 require.True(t, ok) 355 // Tests telegraf config.Duration parsing. 356 require.Equal(t, config.Duration(time.Second), input.WriteTimeout) 357 // Tests telegraf size parsing. 358 require.Equal(t, config.Size(1024*1024), input.MaxBodySize) 359 // Tests toml multiline basic strings on single line. 360 require.Equal(t, "./testdata/special_types.pem", input.TLSCert) 361 // Tests toml multiline basic strings on single line. 362 require.Equal(t, "./testdata/special_types.key", input.TLSKey) 363 // Tests toml multiline basic strings on multiple lines. 364 require.Equal(t, "/path/", strings.TrimRight(input.Paths[0], "\r\n")) 365 } 366 367 func TestConfig_DeprecatedFilters(t *testing.T) { 368 c := config.NewConfig() 369 require.NoError(t, c.LoadConfig("./testdata/deprecated_field_filter.toml")) 370 371 require.Len(t, c.Inputs, 1) 372 require.Equal(t, []string{"foo", "bar", "baz"}, c.Inputs[0].Config.Filter.FieldInclude) 373 require.Equal(t, []string{"foo", "bar", "baz"}, c.Inputs[0].Config.Filter.FieldExclude) 374 } 375 376 func TestConfig_FieldNotDefined(t *testing.T) { 377 tests := []struct { 378 name string 379 filename string 380 expected string 381 }{ 382 { 383 name: "in input plugin without parser", 384 filename: "./testdata/invalid_field.toml", 385 expected: "line 1: configuration specified the fields [\"not_a_field\"], but they were not used. " + 386 "This is either a typo or this config option does not exist in this version.", 387 }, 388 { 389 name: "in input plugin with parser", 390 filename: "./testdata/invalid_field_with_parser.toml", 391 expected: "line 1: configuration specified the fields [\"not_a_field\"], but they were not used. " + 392 "This is either a typo or this config option does not exist in this version.", 393 }, 394 { 395 name: "in input plugin with parser func", 396 filename: "./testdata/invalid_field_with_parserfunc.toml", 397 expected: "line 1: configuration specified the fields [\"not_a_field\"], but they were not used. " + 398 "This is either a typo or this config option does not exist in this version.", 399 }, 400 { 401 name: "in parser of input plugin", 402 filename: "./testdata/invalid_field_in_parser_table.toml", 403 expected: "line 1: configuration specified the fields [\"not_a_field\"], but they were not used. " + 404 "This is either a typo or this config option does not exist in this version.", 405 }, 406 { 407 name: "in parser of input plugin with parser-func", 408 filename: "./testdata/invalid_field_in_parserfunc_table.toml", 409 expected: "line 1: configuration specified the fields [\"not_a_field\"], but they were not used. " + 410 "This is either a typo or this config option does not exist in this version.", 411 }, 412 { 413 name: "in processor plugin without parser", 414 filename: "./testdata/invalid_field_processor.toml", 415 expected: "line 1: configuration specified the fields [\"not_a_field\"], but they were not used. " + 416 "This is either a typo or this config option does not exist in this version.", 417 }, 418 { 419 name: "in processor plugin with parser", 420 filename: "./testdata/invalid_field_processor_with_parser.toml", 421 expected: "line 1: configuration specified the fields [\"not_a_field\"], but they were not used. " + 422 "This is either a typo or this config option does not exist in this version.", 423 }, 424 { 425 name: "in processor plugin with parser func", 426 filename: "./testdata/invalid_field_processor_with_parserfunc.toml", 427 expected: "line 1: configuration specified the fields [\"not_a_field\"], but they were not used. " + 428 "This is either a typo or this config option does not exist in this version.", 429 }, 430 { 431 name: "in parser of processor plugin", 432 filename: "./testdata/invalid_field_processor_in_parser_table.toml", 433 expected: "line 1: configuration specified the fields [\"not_a_field\"], but they were not used. " + 434 "This is either a typo or this config option does not exist in this version.", 435 }, 436 { 437 name: "in parser of processor plugin with parser-func", 438 filename: "./testdata/invalid_field_processor_in_parserfunc_table.toml", 439 expected: "line 1: configuration specified the fields [\"not_a_field\"], but they were not used. " + 440 "This is either a typo or this config option does not exist in this version.", 441 }, 442 } 443 444 for _, tt := range tests { 445 t.Run(tt.name, func(t *testing.T) { 446 c := config.NewConfig() 447 err := c.LoadConfig(tt.filename) 448 require.ErrorContains(t, err, tt.expected) 449 }) 450 } 451 } 452 453 func TestConfig_WrongFieldType(t *testing.T) { 454 c := config.NewConfig() 455 err := c.LoadConfig("./testdata/wrong_field_type.toml") 456 require.Error(t, err, "invalid field type") 457 require.ErrorContains(t, err, "cannot unmarshal TOML string into int") 458 459 c = config.NewConfig() 460 err = c.LoadConfig("./testdata/wrong_field_type2.toml") 461 require.Error(t, err, "invalid field type2") 462 require.ErrorContains(t, err, "cannot unmarshal TOML string into []string") 463 } 464 465 func TestConfig_InlineTables(t *testing.T) { 466 // #4098 467 t.Setenv("TOKEN", "test") 468 469 c := config.NewConfig() 470 require.NoError(t, c.LoadConfig("./testdata/inline_table.toml")) 471 require.Len(t, c.Outputs, 2) 472 473 output, ok := c.Outputs[1].Output.(*MockupOuputPlugin) 474 require.True(t, ok) 475 require.Equal(t, map[string]string{"Authorization": "Token test", "Content-Type": "application/json"}, output.Headers) 476 require.Equal(t, []string{"org_id"}, c.Outputs[0].Config.Filter.TagInclude) 477 } 478 479 func TestConfig_SliceComment(t *testing.T) { 480 t.Skipf("Skipping until #3642 is resolved") 481 482 c := config.NewConfig() 483 require.NoError(t, c.LoadConfig("./testdata/slice_comment.toml")) 484 require.Len(t, c.Outputs, 1) 485 486 output, ok := c.Outputs[0].Output.(*MockupOuputPlugin) 487 require.True(t, ok) 488 require.Equal(t, []string{"test"}, output.Scopes) 489 } 490 491 func TestConfig_BadOrdering(t *testing.T) { 492 // #3444: when not using inline tables, care has to be taken so subsequent configuration 493 // doesn't become part of the table. This is not a bug, but TOML syntax. 494 c := config.NewConfig() 495 err := c.LoadConfig("./testdata/non_slice_slice.toml") 496 require.Error(t, err, "bad ordering") 497 require.Equal( 498 t, 499 "error loading config file ./testdata/non_slice_slice.toml: error parsing http array, line 4: cannot unmarshal TOML array into string (need slice)", 500 err.Error(), 501 ) 502 } 503 504 func TestConfig_AzureMonitorNamespacePrefix(t *testing.T) { 505 // #8256 Cannot use empty string as the namespace prefix 506 c := config.NewConfig() 507 require.NoError(t, c.LoadConfig("./testdata/azure_monitor.toml")) 508 require.Len(t, c.Outputs, 2) 509 510 expectedPrefix := []string{"Telegraf/", ""} 511 for i, plugin := range c.Outputs { 512 output, ok := plugin.Output.(*MockupOuputPlugin) 513 require.True(t, ok) 514 require.Equal(t, expectedPrefix[i], output.NamespacePrefix) 515 } 516 } 517 518 func TestGetDefaultConfigPathFromEnvURL(t *testing.T) { 519 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { 520 w.WriteHeader(http.StatusOK) 521 _, _ = w.Write([]byte("[agent]\ndebug = true")) 522 })) 523 defer ts.Close() 524 525 c := config.NewConfig() 526 t.Setenv("TELEGRAF_CONFIG_PATH", ts.URL) 527 configPath, err := config.GetDefaultConfigPath() 528 require.NoError(t, err) 529 require.Equal(t, []string{ts.URL}, configPath) 530 require.NoError(t, c.LoadConfig(configPath[0])) 531 } 532 533 func TestConfig_URLLikeFileName(t *testing.T) { 534 c := config.NewConfig() 535 err := c.LoadConfig("http:##www.example.com.conf") 536 require.Error(t, err) 537 538 if runtime.GOOS == "windows" { 539 // The error file not found error message is different on Windows 540 require.Equal( 541 t, 542 "error loading config file http:##www.example.com.conf: open http:##www.example.com.conf: The system cannot find the file specified.", 543 err.Error(), 544 ) 545 } else { 546 require.Equal(t, "error loading config file http:##www.example.com.conf: open http:##www.example.com.conf: no such file or directory", err.Error()) 547 } 548 } 549 550 func TestConfig_Filtering(t *testing.T) { 551 c := config.NewConfig() 552 require.NoError(t, c.LoadAll("./testdata/filter_metricpass.toml")) 553 require.Len(t, c.Processors, 1) 554 555 in := []telegraf.Metric{ 556 metric.New( 557 "machine", 558 map[string]string{"state": "on"}, 559 map[string]interface{}{"value": 42.0}, 560 time.Date(2023, time.April, 23, 01, 15, 30, 0, time.UTC), 561 ), 562 metric.New( 563 "machine", 564 map[string]string{"state": "off"}, 565 map[string]interface{}{"value": 23.0}, 566 time.Date(2023, time.April, 23, 23, 59, 01, 0, time.UTC), 567 ), 568 metric.New( 569 "temperature", 570 map[string]string{}, 571 map[string]interface{}{"value": 23.5}, 572 time.Date(2023, time.April, 24, 02, 15, 30, 0, time.UTC), 573 ), 574 } 575 expected := []telegraf.Metric{ 576 metric.New( 577 "machine", 578 map[string]string{ 579 "state": "on", 580 "processed": "yes", 581 }, 582 map[string]interface{}{"value": 42.0}, 583 time.Date(2023, time.April, 23, 01, 15, 30, 0, time.UTC), 584 ), 585 metric.New( 586 "machine", 587 map[string]string{"state": "off"}, 588 map[string]interface{}{"value": 23.0}, 589 time.Date(2023, time.April, 23, 23, 59, 01, 0, time.UTC), 590 ), 591 metric.New( 592 "temperature", 593 map[string]string{ 594 "processed": "yes", 595 }, 596 map[string]interface{}{"value": 23.5}, 597 time.Date(2023, time.April, 24, 02, 15, 30, 0, time.UTC), 598 ), 599 } 600 601 plugin := c.Processors[0] 602 var acc testutil.Accumulator 603 for _, m := range in { 604 require.NoError(t, plugin.Add(m, &acc)) 605 } 606 actual := acc.GetTelegrafMetrics() 607 testutil.RequireMetricsEqual(t, expected, actual, testutil.SortMetrics()) 608 } 609 610 func TestConfig_SerializerInterfaceNewFormat(t *testing.T) { 611 formats := []string{ 612 "carbon2", 613 "csv", 614 "graphite", 615 "influx", 616 "json", 617 "msgpack", 618 "nowmetric", 619 "prometheus", 620 "prometheusremotewrite", 621 "splunkmetric", 622 "wavefront", 623 } 624 625 c := config.NewConfig() 626 require.NoError(t, c.LoadConfig("./testdata/serializers_new.toml")) 627 require.Len(t, c.Outputs, len(formats)) 628 629 cfg := serializers.Config{} 630 override := map[string]struct { 631 param map[string]interface{} 632 mask []string 633 }{} 634 635 expected := make([]telegraf.Serializer, 0, len(formats)) 636 for _, format := range formats { 637 formatCfg := &cfg 638 formatCfg.DataFormat = format 639 640 logger := models.NewLogger("serializers", format, "test") 641 642 var serializer telegraf.Serializer 643 if creator, found := serializers.Serializers[format]; found { 644 t.Logf("new-style %q", format) 645 serializer = creator() 646 } else { 647 t.Logf("old-style %q", format) 648 var err error 649 serializer, err = serializers.NewSerializer(formatCfg) 650 require.NoErrorf(t, err, "No serializer for format %q", format) 651 } 652 653 if settings, found := override[format]; found { 654 s := reflect.Indirect(reflect.ValueOf(serializer)) 655 for key, value := range settings.param { 656 v := reflect.ValueOf(value) 657 s.FieldByName(key).Set(v) 658 } 659 } 660 models.SetLoggerOnPlugin(serializer, logger) 661 if s, ok := serializer.(telegraf.Initializer); ok { 662 require.NoError(t, s.Init()) 663 } 664 expected = append(expected, serializer) 665 } 666 require.Len(t, expected, len(formats)) 667 668 actual := make([]interface{}, 0) 669 for _, plugin := range c.Outputs { 670 output, ok := plugin.Output.(*MockupOutputPluginSerializerNew) 671 require.True(t, ok) 672 // Get the parser set with 'SetParser()' 673 if p, ok := output.Serializer.(*models.RunningSerializer); ok { 674 actual = append(actual, p.Serializer) 675 } else { 676 actual = append(actual, output.Serializer) 677 } 678 } 679 require.Len(t, actual, len(formats)) 680 681 for i, format := range formats { 682 // Determine the underlying type of the serializer 683 stype := reflect.Indirect(reflect.ValueOf(expected[i])).Interface() 684 // Ignore all unexported fields and fields not relevant for functionality 685 options := []cmp.Option{ 686 cmpopts.IgnoreUnexported(stype), 687 cmpopts.IgnoreUnexported(reflect.Indirect(reflect.ValueOf(promserializer.MetricTypes{})).Interface()), 688 cmpopts.IgnoreTypes(sync.Mutex{}, regexp.Regexp{}), 689 cmpopts.IgnoreInterfaces(struct{ telegraf.Logger }{}), 690 } 691 if settings, found := override[format]; found { 692 options = append(options, cmpopts.IgnoreFields(stype, settings.mask...)) 693 } 694 695 // Do a manual comparison as require.EqualValues will also work on unexported fields 696 // that cannot be cleared or ignored. 697 diff := cmp.Diff(expected[i], actual[i], options...) 698 require.Emptyf(t, diff, "Difference in SetSerializer() for %q", format) 699 } 700 } 701 702 func TestConfig_SerializerInterfaceOldFormat(t *testing.T) { 703 formats := []string{ 704 "carbon2", 705 "csv", 706 "graphite", 707 "influx", 708 "json", 709 "msgpack", 710 "nowmetric", 711 "prometheus", 712 "prometheusremotewrite", 713 "splunkmetric", 714 "wavefront", 715 } 716 717 c := config.NewConfig() 718 require.NoError(t, c.LoadConfig("./testdata/serializers_old.toml")) 719 require.Len(t, c.Outputs, len(formats)) 720 721 cfg := serializers.Config{} 722 override := map[string]struct { 723 param map[string]interface{} 724 mask []string 725 }{} 726 727 expected := make([]telegraf.Serializer, 0, len(formats)) 728 for _, format := range formats { 729 formatCfg := &cfg 730 formatCfg.DataFormat = format 731 732 logger := models.NewLogger("serializers", format, "test") 733 734 var serializer serializers.Serializer 735 if creator, found := serializers.Serializers[format]; found { 736 t.Logf("new-style %q", format) 737 serializer = creator() 738 } else { 739 t.Logf("old-style %q", format) 740 var err error 741 serializer, err = serializers.NewSerializer(formatCfg) 742 require.NoErrorf(t, err, "No serializer for format %q", format) 743 } 744 745 if settings, found := override[format]; found { 746 s := reflect.Indirect(reflect.ValueOf(serializer)) 747 for key, value := range settings.param { 748 v := reflect.ValueOf(value) 749 s.FieldByName(key).Set(v) 750 } 751 } 752 models.SetLoggerOnPlugin(serializer, logger) 753 if s, ok := serializer.(telegraf.Initializer); ok { 754 require.NoError(t, s.Init()) 755 } 756 expected = append(expected, serializer) 757 } 758 require.Len(t, expected, len(formats)) 759 760 actual := make([]interface{}, 0) 761 for _, plugin := range c.Outputs { 762 output, ok := plugin.Output.(*MockupOutputPluginSerializerOld) 763 require.True(t, ok) 764 // Get the parser set with 'SetParser()' 765 if p, ok := output.Serializer.(*models.RunningSerializer); ok { 766 actual = append(actual, p.Serializer) 767 } else { 768 actual = append(actual, output.Serializer) 769 } 770 } 771 require.Len(t, actual, len(formats)) 772 773 for i, format := range formats { 774 // Determine the underlying type of the serializer 775 stype := reflect.Indirect(reflect.ValueOf(expected[i])).Interface() 776 // Ignore all unexported fields and fields not relevant for functionality 777 options := []cmp.Option{ 778 cmpopts.IgnoreUnexported(stype), 779 cmpopts.IgnoreUnexported(reflect.Indirect(reflect.ValueOf(promserializer.MetricTypes{})).Interface()), 780 cmpopts.IgnoreTypes(sync.Mutex{}, regexp.Regexp{}), 781 cmpopts.IgnoreInterfaces(struct{ telegraf.Logger }{}), 782 } 783 if settings, found := override[format]; found { 784 options = append(options, cmpopts.IgnoreFields(stype, settings.mask...)) 785 } 786 787 // Do a manual comparison as require.EqualValues will also work on unexported fields 788 // that cannot be cleared or ignored. 789 diff := cmp.Diff(expected[i], actual[i], options...) 790 require.Emptyf(t, diff, "Difference in SetSerializer() for %q", format) 791 } 792 } 793 794 func TestConfig_ParserInterface(t *testing.T) { 795 formats := []string{ 796 "collectd", 797 "csv", 798 "dropwizard", 799 "form_urlencoded", 800 "graphite", 801 "grok", 802 "influx", 803 "json", 804 "json_v2", 805 "logfmt", 806 "nagios", 807 "prometheus", 808 "prometheusremotewrite", 809 "value", 810 "wavefront", 811 "xml", "xpath_json", "xpath_msgpack", "xpath_protobuf", 812 } 813 814 c := config.NewConfig() 815 require.NoError(t, c.LoadConfig("./testdata/parsers_new.toml")) 816 require.Len(t, c.Inputs, len(formats)) 817 818 override := map[string]struct { 819 param map[string]interface{} 820 mask []string 821 }{ 822 "csv": { 823 param: map[string]interface{}{ 824 "HeaderRowCount": 42, 825 }, 826 mask: []string{"TimeFunc", "ResetMode"}, 827 }, 828 "xpath_protobuf": { 829 param: map[string]interface{}{ 830 "ProtobufMessageDef": "testdata/addressbook.proto", 831 "ProtobufMessageType": "addressbook.AddressBook", 832 }, 833 }, 834 } 835 836 expected := make([]telegraf.Parser, 0, len(formats)) 837 for _, format := range formats { 838 logger := models.NewLogger("parsers", format, "parser_test_new") 839 840 creator, found := parsers.Parsers[format] 841 require.Truef(t, found, "No parser for format %q", format) 842 843 parser := creator("parser_test_new") 844 if settings, found := override[format]; found { 845 s := reflect.Indirect(reflect.ValueOf(parser)) 846 for key, value := range settings.param { 847 v := reflect.ValueOf(value) 848 s.FieldByName(key).Set(v) 849 } 850 } 851 models.SetLoggerOnPlugin(parser, logger) 852 if p, ok := parser.(telegraf.Initializer); ok { 853 require.NoError(t, p.Init()) 854 } 855 expected = append(expected, parser) 856 } 857 require.Len(t, expected, len(formats)) 858 859 actual := make([]interface{}, 0) 860 generated := make([]interface{}, 0) 861 for _, plugin := range c.Inputs { 862 input, ok := plugin.Input.(*MockupInputPluginParserNew) 863 require.True(t, ok) 864 // Get the parser set with 'SetParser()' 865 if p, ok := input.Parser.(*models.RunningParser); ok { 866 actual = append(actual, p.Parser) 867 } else { 868 actual = append(actual, input.Parser) 869 } 870 // Get the parser set with 'SetParserFunc()' 871 g, err := input.ParserFunc() 872 require.NoError(t, err) 873 if rp, ok := g.(*models.RunningParser); ok { 874 generated = append(generated, rp.Parser) 875 } else { 876 generated = append(generated, g) 877 } 878 } 879 require.Len(t, actual, len(formats)) 880 881 for i, format := range formats { 882 // Determine the underlying type of the parser 883 stype := reflect.Indirect(reflect.ValueOf(expected[i])).Interface() 884 // Ignore all unexported fields and fields not relevant for functionality 885 options := []cmp.Option{ 886 cmpopts.IgnoreUnexported(stype), 887 cmpopts.IgnoreTypes(sync.Mutex{}), 888 cmpopts.IgnoreInterfaces(struct{ telegraf.Logger }{}), 889 } 890 if settings, found := override[format]; found { 891 options = append(options, cmpopts.IgnoreFields(stype, settings.mask...)) 892 } 893 894 // Do a manual comparison as require.EqualValues will also work on unexported fields 895 // that cannot be cleared or ignored. 896 diff := cmp.Diff(expected[i], actual[i], options...) 897 require.Emptyf(t, diff, "Difference in SetParser() for %q", format) 898 diff = cmp.Diff(expected[i], generated[i], options...) 899 require.Emptyf(t, diff, "Difference in SetParserFunc() for %q", format) 900 } 901 } 902 903 func TestConfig_MultipleProcessorsOrder(t *testing.T) { 904 tests := []struct { 905 name string 906 filename []string 907 expectedOrder []string 908 }{ 909 { 910 name: "Test the order of multiple unique processosr", 911 filename: []string{"multiple_processors.toml"}, 912 expectedOrder: []string{ 913 "processor", 914 "parser_test", 915 "processor_parser", 916 "processor_parserfunc", 917 }, 918 }, 919 { 920 name: "Test using a single 'order' configuration", 921 filename: []string{"multiple_processors_simple_order.toml"}, 922 expectedOrder: []string{ 923 "parser_test", 924 "processor_parser", 925 "processor_parserfunc", 926 "processor", 927 }, 928 }, 929 { 930 name: "Test using multiple 'order' configurations", 931 filename: []string{"multiple_processors_messy_order.toml"}, 932 expectedOrder: []string{ 933 "parser_test", 934 "processor_parserfunc", 935 "processor", 936 "processor_parser", 937 "processor_parser", 938 "processor_parserfunc", 939 }, 940 }, 941 { 942 name: "Test loading multiple configuration files", 943 filename: []string{ 944 "multiple_processors.toml", 945 "multiple_processors_simple_order.toml", 946 }, 947 expectedOrder: []string{ 948 "processor", 949 "parser_test", 950 "processor_parser", 951 "processor_parserfunc", 952 "parser_test", 953 "processor_parser", 954 "processor_parserfunc", 955 "processor", 956 }, 957 }, 958 { 959 name: "Test loading multiple configuration files both with order", 960 filename: []string{ 961 "multiple_processors_simple_order.toml", 962 "multiple_processors_messy_order.toml", 963 }, 964 expectedOrder: []string{ 965 "parser_test", 966 "processor_parser", 967 "processor_parserfunc", 968 "parser_test", 969 "processor_parserfunc", 970 "processor", 971 "processor", 972 "processor_parser", 973 "processor_parser", 974 "processor_parserfunc", 975 }, 976 }, 977 } 978 979 for _, test := range tests { 980 t.Run(test.name, func(t *testing.T) { 981 c := config.NewConfig() 982 filenames := make([]string, 0, len(test.filename)) 983 for _, fn := range test.filename { 984 filenames = append(filenames, filepath.Join(".", "testdata", "processor_order", fn)) 985 } 986 require.NoError(t, c.LoadAll(filenames...)) 987 988 require.Equal(t, len(test.expectedOrder), len(c.Processors)) 989 990 var order []string 991 for _, p := range c.Processors { 992 order = append(order, p.Config.Name) 993 } 994 995 require.Equal(t, test.expectedOrder, order) 996 }) 997 } 998 } 999 1000 func TestConfig_ProcessorsWithParsers(t *testing.T) { 1001 formats := []string{ 1002 "collectd", 1003 "csv", 1004 "dropwizard", 1005 "form_urlencoded", 1006 "graphite", 1007 "grok", 1008 "influx", 1009 "json", 1010 "json_v2", 1011 "logfmt", 1012 "nagios", 1013 "prometheus", 1014 "prometheusremotewrite", 1015 "value", 1016 "wavefront", 1017 "xml", "xpath_json", "xpath_msgpack", "xpath_protobuf", 1018 } 1019 1020 c := config.NewConfig() 1021 require.NoError(t, c.LoadAll("./testdata/processors_with_parsers.toml")) 1022 require.Len(t, c.Processors, len(formats)) 1023 1024 override := map[string]struct { 1025 param map[string]interface{} 1026 mask []string 1027 }{ 1028 "csv": { 1029 param: map[string]interface{}{ 1030 "HeaderRowCount": 42, 1031 }, 1032 mask: []string{"TimeFunc", "ResetMode"}, 1033 }, 1034 "xpath_protobuf": { 1035 param: map[string]interface{}{ 1036 "ProtobufMessageDef": "testdata/addressbook.proto", 1037 "ProtobufMessageType": "addressbook.AddressBook", 1038 }, 1039 }, 1040 } 1041 1042 expected := make([]telegraf.Parser, 0, len(formats)) 1043 for _, format := range formats { 1044 logger := models.NewLogger("parsers", format, "processors_with_parsers") 1045 1046 creator, found := parsers.Parsers[format] 1047 require.Truef(t, found, "No parser for format %q", format) 1048 1049 parser := creator("parser_test") 1050 if settings, found := override[format]; found { 1051 s := reflect.Indirect(reflect.ValueOf(parser)) 1052 for key, value := range settings.param { 1053 v := reflect.ValueOf(value) 1054 s.FieldByName(key).Set(v) 1055 } 1056 } 1057 models.SetLoggerOnPlugin(parser, logger) 1058 if p, ok := parser.(telegraf.Initializer); ok { 1059 require.NoError(t, p.Init()) 1060 } 1061 expected = append(expected, parser) 1062 } 1063 require.Len(t, expected, len(formats)) 1064 1065 actual := make([]interface{}, 0) 1066 generated := make([]interface{}, 0) 1067 for _, plugin := range c.Processors { 1068 var processorIF telegraf.Processor 1069 if p, ok := plugin.Processor.(processors.HasUnwrap); ok { 1070 processorIF = p.Unwrap() 1071 } else { 1072 processorIF = plugin.Processor.(telegraf.Processor) 1073 } 1074 require.NotNil(t, processorIF) 1075 1076 processor, ok := processorIF.(*MockupProcessorPluginParser) 1077 require.True(t, ok) 1078 1079 // Get the parser set with 'SetParser()' 1080 if p, ok := processor.Parser.(*models.RunningParser); ok { 1081 actual = append(actual, p.Parser) 1082 } else { 1083 actual = append(actual, processor.Parser) 1084 } 1085 // Get the parser set with 'SetParserFunc()' 1086 if processor.ParserFunc != nil { 1087 g, err := processor.ParserFunc() 1088 require.NoError(t, err) 1089 if rp, ok := g.(*models.RunningParser); ok { 1090 generated = append(generated, rp.Parser) 1091 } else { 1092 generated = append(generated, g) 1093 } 1094 } else { 1095 generated = append(generated, nil) 1096 } 1097 } 1098 require.Len(t, actual, len(formats)) 1099 1100 for i, format := range formats { 1101 // Determine the underlying type of the parser 1102 stype := reflect.Indirect(reflect.ValueOf(expected[i])).Interface() 1103 // Ignore all unexported fields and fields not relevant for functionality 1104 options := []cmp.Option{ 1105 cmpopts.IgnoreUnexported(stype), 1106 cmpopts.IgnoreTypes(sync.Mutex{}), 1107 cmpopts.IgnoreInterfaces(struct{ telegraf.Logger }{}), 1108 } 1109 if settings, found := override[format]; found { 1110 options = append(options, cmpopts.IgnoreFields(stype, settings.mask...)) 1111 } 1112 1113 // Do a manual comparison as require.EqualValues will also work on unexported fields 1114 // that cannot be cleared or ignored. 1115 diff := cmp.Diff(expected[i], actual[i], options...) 1116 require.Emptyf(t, diff, "Difference in SetParser() for %q", format) 1117 diff = cmp.Diff(expected[i], generated[i], options...) 1118 require.Emptyf(t, diff, "Difference in SetParserFunc() for %q", format) 1119 } 1120 } 1121 1122 func TestConfigPluginIDsDifferent(t *testing.T) { 1123 c := config.NewConfig() 1124 c.Agent.Statefile = "/dev/null" 1125 require.NoError(t, c.LoadConfig("./testdata/state_persistence_input_all_different.toml")) 1126 require.NotEmpty(t, c.Inputs) 1127 1128 // Compare generated IDs 1129 for i, pi := range c.Inputs { 1130 refid := pi.Config.ID 1131 require.NotEmpty(t, refid) 1132 1133 // Cross-comparison 1134 for j, pj := range c.Inputs { 1135 testid := pj.Config.ID 1136 if i == j { 1137 require.Equal(t, refid, testid) 1138 continue 1139 } 1140 require.NotEqualf(t, refid, testid, "equal for %d, %d", i, j) 1141 } 1142 } 1143 } 1144 1145 func TestConfigPluginIDsSame(t *testing.T) { 1146 c := config.NewConfig() 1147 c.Agent.Statefile = "/dev/null" 1148 require.NoError(t, c.LoadConfig("./testdata/state_persistence_input_all_same.toml")) 1149 require.NotEmpty(t, c.Inputs) 1150 1151 // Compare generated IDs 1152 for i, pi := range c.Inputs { 1153 refid := pi.Config.ID 1154 require.NotEmpty(t, refid) 1155 1156 // Cross-comparison 1157 for j, pj := range c.Inputs { 1158 testid := pj.Config.ID 1159 require.Equal(t, refid, testid, "not equal for %d, %d", i, j) 1160 } 1161 } 1162 } 1163 1164 func TestPersisterInputStoreLoad(t *testing.T) { 1165 // Reserve a temporary state file 1166 file, err := os.CreateTemp("", "telegraf_state-*.json") 1167 require.NoError(t, err) 1168 filename := file.Name() 1169 require.NoError(t, file.Close()) 1170 defer os.Remove(filename) 1171 1172 // Load the plugins 1173 cstore := config.NewConfig() 1174 require.NoError(t, cstore.LoadConfig("testdata/state_persistence_input_store_load.toml")) 1175 1176 // Initialize the persister for storing the state 1177 persisterStore := persister.Persister{ 1178 Filename: filename, 1179 } 1180 require.NoError(t, persisterStore.Init()) 1181 1182 expected := make(map[string]interface{}) 1183 for i, plugin := range cstore.Inputs { 1184 require.NoError(t, plugin.Init()) 1185 1186 // Register 1187 p := plugin.Input.(*MockupStatePlugin) 1188 require.NoError(t, persisterStore.Register(plugin.ID(), p)) 1189 1190 // Change the state 1191 p.state.Name += "_" + strings.Repeat("a", i+1) 1192 p.state.Version++ 1193 p.state.Offset += uint64(i + 1) 1194 p.state.Bits = append(p.state.Bits, len(p.state.Bits)) 1195 p.state.Modified, _ = time.Parse(time.RFC3339, "2022-11-03T16:49:00+02:00") 1196 1197 // Store the state for later comparison 1198 expected[plugin.ID()] = p.GetState() 1199 } 1200 1201 // Write state 1202 require.NoError(t, persisterStore.Store()) 1203 1204 // Load the plugins 1205 cload := config.NewConfig() 1206 require.NoError(t, cload.LoadConfig("testdata/state_persistence_input_store_load.toml")) 1207 require.Len(t, cload.Inputs, len(expected)) 1208 1209 // Initialize the persister for loading the state 1210 persisterLoad := persister.Persister{ 1211 Filename: filename, 1212 } 1213 require.NoError(t, persisterLoad.Init()) 1214 1215 for _, plugin := range cload.Inputs { 1216 require.NoError(t, plugin.Init()) 1217 1218 // Register 1219 p := plugin.Input.(*MockupStatePlugin) 1220 require.NoError(t, persisterLoad.Register(plugin.ID(), p)) 1221 1222 // Check that the states are not yet restored 1223 require.NotNil(t, expected[plugin.ID()]) 1224 require.NotEqual(t, expected[plugin.ID()], p.GetState()) 1225 } 1226 1227 // Restore states 1228 require.NoError(t, persisterLoad.Load()) 1229 1230 // Check we got what we saved. 1231 for _, plugin := range cload.Inputs { 1232 p := plugin.Input.(*MockupStatePlugin) 1233 require.Equal(t, expected[plugin.ID()], p.GetState()) 1234 } 1235 } 1236 1237 func TestPersisterProcessorRegistration(t *testing.T) { 1238 // Load the plugins 1239 c := config.NewConfig() 1240 require.NoError(t, c.LoadConfig("testdata/state_persistence_processors.toml")) 1241 require.NotEmpty(t, c.Processors) 1242 require.NotEmpty(t, c.AggProcessors) 1243 1244 // Initialize the persister for test 1245 dut := persister.Persister{ 1246 Filename: "/tmp/doesn_t_matter.json", 1247 } 1248 require.NoError(t, dut.Init()) 1249 1250 // Register the processors 1251 for _, plugin := range c.Processors { 1252 unwrapped := plugin.Processor.(processors.HasUnwrap).Unwrap() 1253 1254 p := unwrapped.(*MockupProcessorPlugin) 1255 require.NoError(t, dut.Register(plugin.ID(), p)) 1256 } 1257 1258 // Register the after-aggregator processors 1259 for _, plugin := range c.AggProcessors { 1260 unwrapped := plugin.Processor.(processors.HasUnwrap).Unwrap() 1261 1262 p := unwrapped.(*MockupProcessorPlugin) 1263 require.NoError(t, dut.Register(plugin.ID(), p)) 1264 } 1265 } 1266 1267 /*** Mockup INPUT plugin for (new) parser testing to avoid cyclic dependencies ***/ 1268 type MockupInputPluginParserNew struct { 1269 Parser telegraf.Parser 1270 ParserFunc telegraf.ParserFunc 1271 } 1272 1273 func (m *MockupInputPluginParserNew) SampleConfig() string { 1274 return "Mockup old parser test plugin" 1275 } 1276 func (m *MockupInputPluginParserNew) Gather(_ telegraf.Accumulator) error { 1277 return nil 1278 } 1279 func (m *MockupInputPluginParserNew) SetParser(parser telegraf.Parser) { 1280 m.Parser = parser 1281 } 1282 func (m *MockupInputPluginParserNew) SetParserFunc(f telegraf.ParserFunc) { 1283 m.ParserFunc = f 1284 } 1285 1286 /*** Mockup INPUT plugin for testing to avoid cyclic dependencies ***/ 1287 type MockupInputPlugin struct { 1288 Servers []string `toml:"servers"` 1289 Methods []string `toml:"methods"` 1290 Timeout config.Duration `toml:"timeout"` 1291 ReadTimeout config.Duration `toml:"read_timeout"` 1292 WriteTimeout config.Duration `toml:"write_timeout"` 1293 MaxBodySize config.Size `toml:"max_body_size"` 1294 Paths []string `toml:"paths"` 1295 Port int `toml:"port"` 1296 Password config.Secret `toml:"password"` 1297 Command string 1298 Files []string 1299 PidFile string 1300 Log telegraf.Logger `toml:"-"` 1301 tls.ServerConfig 1302 1303 parser telegraf.Parser 1304 } 1305 1306 func (m *MockupInputPlugin) SampleConfig() string { 1307 return "Mockup test input plugin" 1308 } 1309 func (m *MockupInputPlugin) Gather(_ telegraf.Accumulator) error { 1310 return nil 1311 } 1312 func (m *MockupInputPlugin) SetParser(parser telegraf.Parser) { 1313 m.parser = parser 1314 } 1315 1316 /*** Mockup INPUT plugin with ParserFunc interface ***/ 1317 type MockupInputPluginParserFunc struct { 1318 parserFunc telegraf.ParserFunc 1319 } 1320 1321 func (m *MockupInputPluginParserFunc) SampleConfig() string { 1322 return "Mockup test input plugin" 1323 } 1324 func (m *MockupInputPluginParserFunc) Gather(_ telegraf.Accumulator) error { 1325 return nil 1326 } 1327 func (m *MockupInputPluginParserFunc) SetParserFunc(pf telegraf.ParserFunc) { 1328 m.parserFunc = pf 1329 } 1330 1331 /*** Mockup INPUT plugin without ParserFunc interface ***/ 1332 type MockupInputPluginParserOnly struct { 1333 parser telegraf.Parser 1334 } 1335 1336 func (m *MockupInputPluginParserOnly) SampleConfig() string { 1337 return "Mockup test input plugin" 1338 } 1339 func (m *MockupInputPluginParserOnly) Gather(_ telegraf.Accumulator) error { 1340 return nil 1341 } 1342 func (m *MockupInputPluginParserOnly) SetParser(p telegraf.Parser) { 1343 m.parser = p 1344 } 1345 1346 /*** Mockup PROCESSOR plugin for testing to avoid cyclic dependencies ***/ 1347 type MockupProcessorPluginParser struct { 1348 Parser telegraf.Parser 1349 ParserFunc telegraf.ParserFunc 1350 } 1351 1352 func (m *MockupProcessorPluginParser) Start(_ telegraf.Accumulator) error { 1353 return nil 1354 } 1355 func (m *MockupProcessorPluginParser) Stop() { 1356 } 1357 func (m *MockupProcessorPluginParser) SampleConfig() string { 1358 return "Mockup test processor plugin with parser" 1359 } 1360 func (m *MockupProcessorPluginParser) Apply(_ ...telegraf.Metric) []telegraf.Metric { 1361 return nil 1362 } 1363 func (m *MockupProcessorPluginParser) Add(_ telegraf.Metric, _ telegraf.Accumulator) error { 1364 return nil 1365 } 1366 func (m *MockupProcessorPluginParser) SetParser(parser telegraf.Parser) { 1367 m.Parser = parser 1368 } 1369 func (m *MockupProcessorPluginParser) SetParserFunc(f telegraf.ParserFunc) { 1370 m.ParserFunc = f 1371 } 1372 1373 /*** Mockup PROCESSOR plugin without parser ***/ 1374 type MockupProcessorPlugin struct { 1375 Option string `toml:"option"` 1376 state []uint64 1377 } 1378 1379 func (m *MockupProcessorPlugin) Start(_ telegraf.Accumulator) error { 1380 return nil 1381 } 1382 func (m *MockupProcessorPlugin) Stop() { 1383 } 1384 func (m *MockupProcessorPlugin) SampleConfig() string { 1385 return "Mockup test processor plugin with parser" 1386 } 1387 func (m *MockupProcessorPlugin) Apply(in ...telegraf.Metric) []telegraf.Metric { 1388 out := make([]telegraf.Metric, 0, len(in)) 1389 for _, m := range in { 1390 m.AddTag("processed", "yes") 1391 out = append(out, m) 1392 } 1393 return out 1394 } 1395 func (m *MockupProcessorPlugin) GetState() interface{} { 1396 return m.state 1397 } 1398 func (m *MockupProcessorPlugin) SetState(state interface{}) error { 1399 s, ok := state.([]uint64) 1400 if !ok { 1401 return fmt.Errorf("invalid state type %T", state) 1402 } 1403 m.state = s 1404 1405 return nil 1406 } 1407 1408 /*** Mockup PROCESSOR plugin with parser ***/ 1409 type MockupProcessorPluginParserOnly struct { 1410 Parser telegraf.Parser 1411 } 1412 1413 func (m *MockupProcessorPluginParserOnly) Start(_ telegraf.Accumulator) error { 1414 return nil 1415 } 1416 func (m *MockupProcessorPluginParserOnly) Stop() { 1417 } 1418 func (m *MockupProcessorPluginParserOnly) SampleConfig() string { 1419 return "Mockup test processor plugin with parser" 1420 } 1421 func (m *MockupProcessorPluginParserOnly) Apply(_ ...telegraf.Metric) []telegraf.Metric { 1422 return nil 1423 } 1424 func (m *MockupProcessorPluginParserOnly) Add(_ telegraf.Metric, _ telegraf.Accumulator) error { 1425 return nil 1426 } 1427 func (m *MockupProcessorPluginParserOnly) SetParser(parser telegraf.Parser) { 1428 m.Parser = parser 1429 } 1430 1431 /*** Mockup PROCESSOR plugin with parser-function ***/ 1432 type MockupProcessorPluginParserFunc struct { 1433 Parser telegraf.ParserFunc 1434 } 1435 1436 func (m *MockupProcessorPluginParserFunc) Start(_ telegraf.Accumulator) error { 1437 return nil 1438 } 1439 func (m *MockupProcessorPluginParserFunc) Stop() { 1440 } 1441 func (m *MockupProcessorPluginParserFunc) SampleConfig() string { 1442 return "Mockup test processor plugin with parser" 1443 } 1444 func (m *MockupProcessorPluginParserFunc) Apply(_ ...telegraf.Metric) []telegraf.Metric { 1445 return nil 1446 } 1447 func (m *MockupProcessorPluginParserFunc) Add(_ telegraf.Metric, _ telegraf.Accumulator) error { 1448 return nil 1449 } 1450 func (m *MockupProcessorPluginParserFunc) SetParserFunc(pf telegraf.ParserFunc) { 1451 m.Parser = pf 1452 } 1453 1454 /*** Mockup OUTPUT plugin for testing to avoid cyclic dependencies ***/ 1455 type MockupOuputPlugin struct { 1456 URL string `toml:"url"` 1457 Headers map[string]string `toml:"headers"` 1458 Scopes []string `toml:"scopes"` 1459 NamespacePrefix string `toml:"namespace_prefix"` 1460 Log telegraf.Logger `toml:"-"` 1461 tls.ClientConfig 1462 } 1463 1464 func (m *MockupOuputPlugin) Connect() error { 1465 return nil 1466 } 1467 func (m *MockupOuputPlugin) Close() error { 1468 return nil 1469 } 1470 func (m *MockupOuputPlugin) SampleConfig() string { 1471 return "Mockup test output plugin" 1472 } 1473 func (m *MockupOuputPlugin) Write(_ []telegraf.Metric) error { 1474 return nil 1475 } 1476 1477 /*** Mockup OUTPUT plugin for serializer testing to avoid cyclic dependencies ***/ 1478 type MockupOutputPluginSerializerOld struct { 1479 Serializer serializers.Serializer 1480 } 1481 1482 func (m *MockupOutputPluginSerializerOld) SetSerializer(s serializers.Serializer) { 1483 m.Serializer = s 1484 } 1485 func (*MockupOutputPluginSerializerOld) Connect() error { 1486 return nil 1487 } 1488 func (*MockupOutputPluginSerializerOld) Close() error { 1489 return nil 1490 } 1491 func (*MockupOutputPluginSerializerOld) SampleConfig() string { 1492 return "Mockup test output plugin" 1493 } 1494 func (*MockupOutputPluginSerializerOld) Write(_ []telegraf.Metric) error { 1495 return nil 1496 } 1497 1498 type MockupOutputPluginSerializerNew struct { 1499 Serializer telegraf.Serializer 1500 } 1501 1502 func (m *MockupOutputPluginSerializerNew) SetSerializer(s telegraf.Serializer) { 1503 m.Serializer = s 1504 } 1505 func (*MockupOutputPluginSerializerNew) Connect() error { 1506 return nil 1507 } 1508 func (*MockupOutputPluginSerializerNew) Close() error { 1509 return nil 1510 } 1511 func (*MockupOutputPluginSerializerNew) SampleConfig() string { 1512 return "Mockup test output plugin" 1513 } 1514 func (*MockupOutputPluginSerializerNew) Write(_ []telegraf.Metric) error { 1515 return nil 1516 } 1517 1518 /*** Mockup INPUT plugin with state for testing to avoid cyclic dependencies ***/ 1519 type MockupState struct { 1520 Name string 1521 Version uint64 1522 Offset uint64 1523 Bits []int 1524 Modified time.Time 1525 } 1526 1527 type MockupStatePluginSettings struct { 1528 Name string `toml:"name"` 1529 Factor float64 `toml:"factor"` 1530 Enabled bool `toml:"enabled"` 1531 BitField []int `toml:"bits"` 1532 } 1533 1534 type MockupStatePlugin struct { 1535 Servers []string `toml:"servers"` 1536 Method string `toml:"method"` 1537 Settings map[string]string `toml:"params"` 1538 Port int `toml:"port"` 1539 Setups []MockupStatePluginSettings `toml:"setup"` 1540 state MockupState 1541 } 1542 1543 func (m *MockupStatePlugin) Init() error { 1544 t0, _ := time.Parse(time.RFC3339, "2021-04-24T23:42:00+02:00") 1545 m.state = MockupState{ 1546 Name: "mockup", 1547 Bits: []int{}, 1548 Modified: t0, 1549 } 1550 1551 return nil 1552 } 1553 1554 func (m *MockupStatePlugin) GetState() interface{} { 1555 return m.state 1556 } 1557 1558 func (m *MockupStatePlugin) SetState(state interface{}) error { 1559 s, ok := state.(MockupState) 1560 if !ok { 1561 return fmt.Errorf("invalid state type %T", state) 1562 } 1563 m.state = s 1564 1565 return nil 1566 } 1567 1568 func (m *MockupStatePlugin) SampleConfig() string { 1569 return "Mockup test plugin" 1570 } 1571 1572 func (m *MockupStatePlugin) Gather(_ telegraf.Accumulator) error { 1573 return nil 1574 } 1575 1576 // Register the mockup plugin on loading 1577 func init() { 1578 // Register the mockup input plugin for the required names 1579 inputs.Add("parser_test_new", func() telegraf.Input { 1580 return &MockupInputPluginParserNew{} 1581 }) 1582 inputs.Add("parser", func() telegraf.Input { 1583 return &MockupInputPluginParserOnly{} 1584 }) 1585 inputs.Add("parser_func", func() telegraf.Input { 1586 return &MockupInputPluginParserFunc{} 1587 }) 1588 inputs.Add("exec", func() telegraf.Input { 1589 return &MockupInputPlugin{Timeout: config.Duration(time.Second * 5)} 1590 }) 1591 inputs.Add("file", func() telegraf.Input { 1592 return &MockupInputPlugin{} 1593 }) 1594 inputs.Add("http_listener_v2", func() telegraf.Input { 1595 return &MockupInputPlugin{} 1596 }) 1597 inputs.Add("memcached", func() telegraf.Input { 1598 return &MockupInputPlugin{} 1599 }) 1600 inputs.Add("procstat", func() telegraf.Input { 1601 return &MockupInputPlugin{} 1602 }) 1603 inputs.Add("statetest", func() telegraf.Input { 1604 return &MockupStatePlugin{} 1605 }) 1606 1607 // Register the mockup processor plugin for the required names 1608 processors.Add("parser_test", func() telegraf.Processor { 1609 return &MockupProcessorPluginParser{} 1610 }) 1611 processors.Add("processor", func() telegraf.Processor { 1612 return &MockupProcessorPlugin{} 1613 }) 1614 processors.Add("processor_parser", func() telegraf.Processor { 1615 return &MockupProcessorPluginParserOnly{} 1616 }) 1617 processors.Add("processor_parserfunc", func() telegraf.Processor { 1618 return &MockupProcessorPluginParserFunc{} 1619 }) 1620 processors.Add("statetest", func() telegraf.Processor { 1621 return &MockupProcessorPlugin{} 1622 }) 1623 1624 // Register the mockup output plugin for the required names 1625 outputs.Add("azure_monitor", func() telegraf.Output { 1626 return &MockupOuputPlugin{NamespacePrefix: "Telegraf/"} 1627 }) 1628 outputs.Add("http", func() telegraf.Output { 1629 return &MockupOuputPlugin{} 1630 }) 1631 outputs.Add("serializer_test_new", func() telegraf.Output { 1632 return &MockupOutputPluginSerializerNew{} 1633 }) 1634 outputs.Add("serializer_test_old", func() telegraf.Output { 1635 return &MockupOutputPluginSerializerOld{} 1636 }) 1637 }