feat: generate the plugins sample config (#10886)

This commit is contained in:
Sebastian Spaink 2022-04-05 17:11:09 -05:00 committed by GitHub
parent 6cb25207fd
commit 5d6748fcb5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 389 additions and 117 deletions

View File

@ -78,6 +78,7 @@ commands:
key: windows-go-<< parameters.cache_version >>-{{ checksum "go.sum" }} key: windows-go-<< parameters.cache_version >>-{{ checksum "go.sum" }}
- run: 'sh ./scripts/installgo_windows.sh' - run: 'sh ./scripts/installgo_windows.sh'
- run: choco install mingw - run: choco install mingw
- run: 'make generate'
- run: mkdir -p test-results - run: mkdir -p test-results
- run: ./scripts/install_gotestsum.sh << parameters.os >> << parameters.gotestsum >> - run: ./scripts/install_gotestsum.sh << parameters.os >> << parameters.gotestsum >>
- unless: - unless:
@ -120,7 +121,7 @@ commands:
paths: paths:
- 'C:\Go' - 'C:\Go'
- 'C:\Users\circleci\project\gotestsum.exe' - 'C:\Users\circleci\project\gotestsum.exe'
- run: 'make generate-clean'
package-build: package-build:
parameters: parameters:
type: type:

View File

@ -109,10 +109,21 @@ versioninfo:
go run scripts/generate_versioninfo/main.go; \ go run scripts/generate_versioninfo/main.go; \
go generate cmd/telegraf/telegraf_windows.go; \ go generate cmd/telegraf/telegraf_windows.go; \
.PHONY: telegraf .PHONY: generate
telegraf: generate:
go generate -run="plugindata/main.go$$" ./plugins/inputs/... ./plugins/outputs/... ./plugins/processors/... ./plugins/aggregators/...
.PHONY: generate-clean
generate-clean:
go generate -run="plugindata/main.go --clean" ./plugins/inputs/... ./plugins/outputs/... ./plugins/processors/... ./plugins/aggregators/...
.PHONY: build
build:
go build -ldflags "$(LDFLAGS)" ./cmd/telegraf go build -ldflags "$(LDFLAGS)" ./cmd/telegraf
.PHONY: telegraf
telegraf: generate build generate-clean
# Used by dockerfile builds # Used by dockerfile builds
.PHONY: go-install .PHONY: go-install
go-install: go-install:
@ -312,7 +323,7 @@ darwin-arm64:
include_packages := $(mips) $(mipsel) $(arm64) $(amd64) $(static) $(armel) $(armhf) $(riscv64) $(s390x) $(ppc64le) $(i386) $(windows) $(darwin-amd64) $(darwin-arm64) include_packages := $(mips) $(mipsel) $(arm64) $(amd64) $(static) $(armel) $(armhf) $(riscv64) $(s390x) $(ppc64le) $(i386) $(windows) $(darwin-amd64) $(darwin-arm64)
.PHONY: package .PHONY: package
package: $(include_packages) package: generate $(include_packages) generate-clean
.PHONY: $(include_packages) .PHONY: $(include_packages)
$(include_packages): $(include_packages):

View File

@ -678,23 +678,24 @@ func printConfig(name string, p telegraf.PluginDescriber, op string, commented b
if commented { if commented {
comment = "# " comment = "# "
} }
fmt.Printf("\n%s# %s\n%s[[%s.%s]]", comment, p.Description(), comment, op, name)
if di.Since != "" { if di.Since != "" {
removalNote := "" removalNote := ""
if di.RemovalIn != "" { if di.RemovalIn != "" {
removalNote = " and will be removed in " + di.RemovalIn removalNote = " and will be removed in " + di.RemovalIn
} }
fmt.Printf("\n%s ## DEPRECATED: The '%s' plugin is deprecated in version %s%s, %s.", comment, name, di.Since, removalNote, di.Notice) fmt.Printf("\n%s ## DEPRECATED: The '%s' plugin is deprecated in version %s%s, %s.", comment, name, di.Since, removalNote, di.Notice)
} }
config := p.SampleConfig() config := p.SampleConfig()
if config == "" { if config == "" {
fmt.Printf("\n#[[%s.%s]]", op, name)
fmt.Printf("\n%s # no configuration\n\n", comment) fmt.Printf("\n%s # no configuration\n\n", comment)
} else { } else {
lines := strings.Split(config, "\n") lines := strings.Split(config, "\n")
fmt.Print("\n")
for i, line := range lines { for i, line := range lines {
if i == 0 || i == len(lines)-1 { if i == len(lines)-1 {
fmt.Print("\n") fmt.Print("\n")
continue continue
} }

View File

@ -678,7 +678,6 @@ type MockupInputPluginParserOld struct {
} }
func (m *MockupInputPluginParserOld) SampleConfig() string { return "Mockup old parser test plugin" } func (m *MockupInputPluginParserOld) SampleConfig() string { return "Mockup old parser test plugin" }
func (m *MockupInputPluginParserOld) Description() string { return "Mockup old parser test plugin" }
func (m *MockupInputPluginParserOld) Gather(acc telegraf.Accumulator) error { return nil } func (m *MockupInputPluginParserOld) Gather(acc telegraf.Accumulator) error { return nil }
func (m *MockupInputPluginParserOld) SetParser(parser parsers.Parser) { m.Parser = parser } func (m *MockupInputPluginParserOld) SetParser(parser parsers.Parser) { m.Parser = parser }
func (m *MockupInputPluginParserOld) SetParserFunc(f parsers.ParserFunc) { m.ParserFunc = f } func (m *MockupInputPluginParserOld) SetParserFunc(f parsers.ParserFunc) { m.ParserFunc = f }
@ -690,7 +689,6 @@ type MockupInputPluginParserNew struct {
} }
func (m *MockupInputPluginParserNew) SampleConfig() string { return "Mockup old parser test plugin" } func (m *MockupInputPluginParserNew) SampleConfig() string { return "Mockup old parser test plugin" }
func (m *MockupInputPluginParserNew) Description() string { return "Mockup old parser test plugin" }
func (m *MockupInputPluginParserNew) Gather(acc telegraf.Accumulator) error { return nil } func (m *MockupInputPluginParserNew) Gather(acc telegraf.Accumulator) error { return nil }
func (m *MockupInputPluginParserNew) SetParser(parser telegraf.Parser) { m.Parser = parser } func (m *MockupInputPluginParserNew) SetParser(parser telegraf.Parser) { m.Parser = parser }
func (m *MockupInputPluginParserNew) SetParserFunc(f telegraf.ParserFunc) { m.ParserFunc = f } func (m *MockupInputPluginParserNew) SetParserFunc(f telegraf.ParserFunc) { m.ParserFunc = f }
@ -714,7 +712,6 @@ type MockupInputPlugin struct {
} }
func (m *MockupInputPlugin) SampleConfig() string { return "Mockup test input plugin" } func (m *MockupInputPlugin) SampleConfig() string { return "Mockup test input plugin" }
func (m *MockupInputPlugin) Description() string { return "Mockup test input plugin" }
func (m *MockupInputPlugin) Gather(acc telegraf.Accumulator) error { return nil } func (m *MockupInputPlugin) Gather(acc telegraf.Accumulator) error { return nil }
func (m *MockupInputPlugin) SetParser(parser telegraf.Parser) { m.parser = parser } func (m *MockupInputPlugin) SetParser(parser telegraf.Parser) { m.parser = parser }
@ -730,7 +727,6 @@ type MockupOuputPlugin struct {
func (m *MockupOuputPlugin) Connect() error { return nil } func (m *MockupOuputPlugin) Connect() error { return nil }
func (m *MockupOuputPlugin) Close() error { return nil } func (m *MockupOuputPlugin) Close() error { return nil }
func (m *MockupOuputPlugin) Description() string { return "Mockup test output plugin" }
func (m *MockupOuputPlugin) SampleConfig() string { return "Mockup test output plugin" } func (m *MockupOuputPlugin) SampleConfig() string { return "Mockup test output plugin" }
func (m *MockupOuputPlugin) Write(metrics []telegraf.Metric) error { return nil } func (m *MockupOuputPlugin) Write(metrics []telegraf.Metric) error { return nil }

View File

@ -9,10 +9,10 @@ This section is for developers who want to create a new aggregator plugin.
register themselves. See below for a quick example. register themselves. See below for a quick example.
* To be available within Telegraf itself, plugins must add themselves to the * To be available within Telegraf itself, plugins must add themselves to the
`github.com/influxdata/telegraf/plugins/aggregators/all/all.go` file. `github.com/influxdata/telegraf/plugins/aggregators/all/all.go` file.
* The `SampleConfig` function should return valid toml that describes how the * Each plugin requires a file called `<plugin_name>_sample_config.go`, where `<plugin_name>` is replaced with the actual plugin name.
plugin can be configured. This is included in `telegraf config`. Please Copy the [example template](#sample-configuration-template) into this file, also updating `<plugin_name>` were appropriate.
consult the [Sample Config][] page for the latest style guidelines. This file is automatically updated during the build process to include the sample configuration from the `README.md`.
* The `Description` function should say in one line what this aggregator does. Please consult the [Sample Config][] page for the latest style guidelines.
* The Aggregator plugin will need to keep caches of metrics that have passed * The Aggregator plugin will need to keep caches of metrics that have passed
through it. This should be done using the builtin `HashID()` function of through it. This should be done using the builtin `HashID()` function of
each metric. each metric.
@ -22,6 +22,8 @@ This section is for developers who want to create a new aggregator plugin.
### Aggregator Plugin Example ### Aggregator Plugin Example
```go ```go
//go:generate go run ../../../tools/generate_plugindata/main.go
//go:generate go run ../../../tools/generate_plugindata/main.go --clean
package min package min
// min.go // min.go
@ -44,26 +46,10 @@ func NewMin() telegraf.Aggregator {
return m return m
} }
var sampleConfig = `
## period is the flush & clear interval of the aggregator.
period = "30s"
## If true drop_original will drop the original metrics and
## only send aggregates.
drop_original = false
`
func (m *Min) Init() error { func (m *Min) Init() error {
return nil return nil
} }
func (m *Min) SampleConfig() string {
return sampleConfig
}
func (m *Min) Description() string {
return "Keep the aggregate min of each metric passing through."
}
func (m *Min) Add(in telegraf.Metric) { func (m *Min) Add(in telegraf.Metric) {
id := in.HashID() id := in.HashID()
if _, ok := m.nameCache[id]; !ok { if _, ok := m.nameCache[id]; !ok {
@ -127,6 +113,19 @@ func init() {
} }
``` ```
### Sample Configuration Template
```go
//go:generate go run ../../../tools/generate_plugindata/main.go
//go:generate go run ../../../tools/generate_plugindata/main.go --clean
// DON'T EDIT; This file is used as a template by tools/generate_plugindata
package <plugin_package>
func (k *<plugin_struct>) SampleConfig() string {
return `{{ .SampleConfig }}`
}
```
[telegraf.Aggregator]: https://godoc.org/github.com/influxdata/telegraf#Aggregator [telegraf.Aggregator]: https://godoc.org/github.com/influxdata/telegraf#Aggregator
[Sample Config]: https://github.com/influxdata/telegraf/blob/master/docs/developers/SAMPLE_CONFIG.md [Sample Config]: https://github.com/influxdata/telegraf/blob/master/docs/developers/SAMPLE_CONFIG.md
[Code Style]: https://github.com/influxdata/telegraf/blob/master/docs/developers/CODE_STYLE.md [Code Style]: https://github.com/influxdata/telegraf/blob/master/docs/developers/CODE_STYLE.md

View File

@ -15,11 +15,10 @@ and submit new inputs.
themselves. See below for a quick example. themselves. See below for a quick example.
- Input Plugins must be added to the - Input Plugins must be added to the
`github.com/influxdata/telegraf/plugins/inputs/all/all.go` file. `github.com/influxdata/telegraf/plugins/inputs/all/all.go` file.
- The `SampleConfig` function should return valid toml that describes how the - Each plugin requires a file called `<plugin_name>_sample_config.go`, where `<plugin_name>` is replaced with the actual plugin name.
plugin can be configured. This is included in `telegraf config`. Please Copy the [example template](#sample-configuration-template) into this file, also updating `<plugin_name>` were appropriate.
consult the [Sample Config][] page for the latest style This file is automatically updated during the build process to include the sample configuration from the `README.md`.
guidelines. Please consult the [Sample Config][] page for the latest style guidelines.
- The `Description` function should say in one line what this plugin does.
- Follow the recommended [Code Style][]. - Follow the recommended [Code Style][].
Let's say you've written a plugin that emits metrics about processes on the Let's say you've written a plugin that emits metrics about processes on the
@ -28,10 +27,10 @@ current host.
## Input Plugin Example ## Input Plugin Example
```go ```go
//go:generate go run ../../../tools/generate_plugindata/main.go
//go:generate go run ../../../tools/generate_plugindata/main.go --clean
package simple package simple
// simple.go
import ( import (
"github.com/influxdata/telegraf" "github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/plugins/inputs" "github.com/influxdata/telegraf/plugins/inputs"
@ -42,17 +41,6 @@ type Simple struct {
Log telegraf.Logger `toml:"-"` Log telegraf.Logger `toml:"-"`
} }
func (s *Simple) Description() string {
return "a demo plugin"
}
func (s *Simple) SampleConfig() string {
return `
## Indicate if everything is fine
ok = true
`
}
// Init is for setup, and validating config. // Init is for setup, and validating config.
func (s *Simple) Init() error { func (s *Simple) Init() error {
return nil return nil
@ -73,6 +61,17 @@ func init() {
} }
``` ```
```go
//go:generate go run ../../../tools/generate_plugindata/main.go
//go:generate go run ../../../tools/generate_plugindata/main.go --clean
// DON'T EDIT; This file is used as a template by tools/generate_plugindata
package <plugin_package>
func (k *<plugin_struct>) SampleConfig() string {
return `{{ .SampleConfig }}`
}
```
### Development ### Development
- Run `make static` followed by `make plugin-[pluginName]` to spin up a docker - Run `make static` followed by `make plugin-[pluginName]` to spin up a docker
@ -101,7 +100,7 @@ You can then utilize the parser internally in your plugin, parsing data as you
see fit. Telegraf's configuration layer will take care of instantiating and see fit. Telegraf's configuration layer will take care of instantiating and
creating the `Parser` object. creating the `Parser` object.
Add the following to the `SampleConfig()`: Add the following to the sample configuration in the README.md:
```toml ```toml
## Data format to consume. ## Data format to consume.

View File

@ -11,15 +11,17 @@ similar constructs.
themselves. See below for a quick example. themselves. See below for a quick example.
- To be available within Telegraf itself, plugins must add themselves to the - To be available within Telegraf itself, plugins must add themselves to the
`github.com/influxdata/telegraf/plugins/outputs/all/all.go` file. `github.com/influxdata/telegraf/plugins/outputs/all/all.go` file.
- The `SampleConfig` function should return valid toml that describes how the - Each plugin requires a file called `<plugin_name>_sample_config.go`, where `<plugin_name>` is replaced with the actual plugin name.
plugin can be configured. This is included in `telegraf config`. Please Copy the [example template](#sample-configuration-template) into this file, also updating `<plugin_name>` were appropriate.
consult the [Sample Config][] page for the latest style guidelines. This file is automatically updated during the build process to include the sample configuration from the `README.md`.
- The `Description` function should say in one line what this output does. Please consult the [Sample Config][] page for the latest style guidelines.
- Follow the recommended [Code Style][]. - Follow the recommended [Code Style][].
## Output Plugin Example ## Output Plugin Example
```go ```go
//go:generate go run ../../../tools/generate_plugindata/main.go
//go:generate go run ../../../tools/generate_plugindata/main.go --clean
package simpleoutput package simpleoutput
// simpleoutput.go // simpleoutput.go
@ -34,16 +36,6 @@ type Simple struct {
Log telegraf.Logger `toml:"-"` Log telegraf.Logger `toml:"-"`
} }
func (s *Simple) Description() string {
return "a demo output"
}
func (s *Simple) SampleConfig() string {
return `
ok = true
`
}
// Init is for setup, and validating config. // Init is for setup, and validating config.
func (s *Simple) Init() error { func (s *Simple) Init() error {
return nil return nil
@ -76,6 +68,19 @@ func init() {
``` ```
### Sample Configuration Template
```go
//go:generate go run ../../../tools/generate_plugindata/main.go
//go:generate go run ../../../tools/generate_plugindata/main.go --clean
// DON'T EDIT; This file is used as a template by tools/generate_plugindata
package <plugin_package>
func (k *<plugin_struct>) SampleConfig() string {
return `{{ .SampleConfig }}`
}
```
## Data Formats ## Data Formats
Some output plugins, such as the [file][] plugin, can write in any supported Some output plugins, such as the [file][] plugin, can write in any supported

View File

@ -9,18 +9,17 @@ This section is for developers who want to create a new processor plugin.
themselves. See below for a quick example. themselves. See below for a quick example.
* To be available within Telegraf itself, plugins must add themselves to the * To be available within Telegraf itself, plugins must add themselves to the
`github.com/influxdata/telegraf/plugins/processors/all/all.go` file. `github.com/influxdata/telegraf/plugins/processors/all/all.go` file.
* The `SampleConfig` function should return valid toml that describes how the * Each plugin requires a file called `<plugin_name>_sample_config.go`, where `<plugin_name>` is replaced with the actual plugin name.
processor can be configured. This is include in the output of `telegraf Copy the [example template](#sample-configuration-template) into this file, also updating `<plugin_name>` were appropriate.
config`. This file is automatically updated during the build process to include the sample configuration from the `README.md`.
* The `SampleConfig` function should return valid toml that describes how the Please consult the [Sample Config][] page for the latest style guidelines.
plugin can be configured. This is included in `telegraf config`. Please
consult the [Sample Config][] page for the latest style guidelines.
* The `Description` function should say in one line what this processor does.
* Follow the recommended [Code Style][]. * Follow the recommended [Code Style][].
## Processor Plugin Example ## Processor Plugin Example
```go ```go
//go:generate go run ../../../tools/generate_plugindata/main.go
//go:generate go run ../../../tools/generate_plugindata/main.go --clean
package printer package printer
// printer.go // printer.go
@ -36,17 +35,6 @@ type Printer struct {
Log telegraf.Logger `toml:"-"` Log telegraf.Logger `toml:"-"`
} }
var sampleConfig = `
`
func (p *Printer) SampleConfig() string {
return sampleConfig
}
func (p *Printer) Description() string {
return "Print all metrics that pass through this filter."
}
// Init is for setup, and validating config. // Init is for setup, and validating config.
func (p *Printer) Init() error { func (p *Printer) Init() error {
return nil return nil
@ -66,6 +54,19 @@ func init() {
} }
``` ```
### Sample Configuration Template
```go
//go:generate go run ../../../tools/generate_plugindata/main.go
//go:generate go run ../../../tools/generate_plugindata/main.go --clean
// DON'T EDIT; This file is used as a template by tools/generate_plugindata
package <plugin_package>
func (k *<plugin_struct>) SampleConfig() string {
return `{{ .SampleConfig }}`
}
```
## Streaming Processors ## Streaming Processors
Streaming processors are a new processor type available to you. They are Streaming processors are a new processor type available to you. They are
@ -102,17 +103,6 @@ type Printer struct {
Log telegraf.Logger `toml:"-"` Log telegraf.Logger `toml:"-"`
} }
var sampleConfig = `
`
func (p *Printer) SampleConfig() string {
return sampleConfig
}
func (p *Printer) Description() string {
return "Print all metrics that pass through this filter."
}
// Init is for setup, and validating config. // Init is for setup, and validating config.
func (p *Printer) Init() error { func (p *Printer) Init() error {
return nil return nil

View File

@ -1,7 +1,6 @@
# Sample Configuration # Sample Configuration
The sample config file is generated from a results of the `SampleConfig()` and The sample config file is generated from a results of the `SampleConfig()` functions of the plugin.
`Description()` functions of the plugins.
You can generate a full sample You can generate a full sample
config: config:

1
go.mod
View File

@ -137,6 +137,7 @@ require (
github.com/wavefronthq/wavefront-sdk-go v0.9.10 github.com/wavefronthq/wavefront-sdk-go v0.9.10
github.com/wvanbergen/kafka v0.0.0-20171203153745-e2edea948ddf github.com/wvanbergen/kafka v0.0.0-20171203153745-e2edea948ddf
github.com/xdg/scram v1.0.3 github.com/xdg/scram v1.0.3
github.com/yuin/goldmark v1.4.1
go.mongodb.org/mongo-driver v1.8.3 go.mongodb.org/mongo-driver v1.8.3
go.opentelemetry.io/collector/model v0.44.0 go.opentelemetry.io/collector/model v0.44.0
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.27.0 go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.27.0

1
go.sum
View File

@ -2261,6 +2261,7 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.1 h1:/vn0k+RBvwlxEmP5E7SZMqNxPhfMVFEJiykr15/0XKM=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/gopher-lua v0.0.0-20200603152657-dc2b0ca8b37e/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ= github.com/yuin/gopher-lua v0.0.0-20200603152657-dc2b0ca8b37e/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ=
github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da h1:NimzV1aGyq29m5ukMK0AMWEhFaL/lrEOaephfuoiARg= github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da h1:NimzV1aGyq29m5ukMK0AMWEhFaL/lrEOaephfuoiARg=

View File

@ -26,11 +26,8 @@ type Initializer interface {
// not part of the interface, but will receive an injected logger if it's set. // not part of the interface, but will receive an injected logger if it's set.
// eg: Log telegraf.Logger `toml:"-"` // eg: Log telegraf.Logger `toml:"-"`
type PluginDescriber interface { type PluginDescriber interface {
// SampleConfig returns the default configuration of the Processor // SampleConfig returns the default configuration of the Plugin
SampleConfig() string SampleConfig() string
// Description returns a one-sentence description on the Processor
Description() string
} }
// Logger defines an plugin-related interface for logging. // Logger defines an plugin-related interface for logging.

View File

@ -34,16 +34,6 @@ func TestLoadConfig(t *testing.T) {
require.Equal(t, `test"\test`, inp.SecretValue) require.Equal(t, `test"\test`, inp.SecretValue)
} }
func TestDefaultImportedPluginsSelfRegisters(t *testing.T) {
inputs.Add("test", func() telegraf.Input {
return &testInput{}
})
cfg, err := LoadConfig(nil)
require.NoError(t, err)
require.Equal(t, "test", cfg.Input.Description())
}
func TestLoadingSpecialTypes(t *testing.T) { func TestLoadingSpecialTypes(t *testing.T) {
inputs.Add("test", func() telegraf.Input { inputs.Add("test", func() telegraf.Input {
return &testDurationInput{} return &testDurationInput{}

View File

@ -66,10 +66,6 @@ func (i *erroringInput) SampleConfig() string {
return "" return ""
} }
func (i *erroringInput) Description() string {
return ""
}
func (i *erroringInput) Gather(acc telegraf.Accumulator) error { func (i *erroringInput) Gather(acc telegraf.Accumulator) error {
acc.AddError(errors.New("intentional")) acc.AddError(errors.New("intentional"))
return nil return nil

View File

@ -24,10 +24,6 @@ func (sp *streamingProcessor) SampleConfig() string {
return sp.processor.SampleConfig() return sp.processor.SampleConfig()
} }
func (sp *streamingProcessor) Description() string {
return sp.processor.Description()
}
func (sp *streamingProcessor) Start(acc telegraf.Accumulator) error { func (sp *streamingProcessor) Start(acc telegraf.Accumulator) error {
sp.acc = acc sp.acc = acc
return nil return nil

View File

@ -0,0 +1,157 @@
// generate_plugindata is a tool used to inject the sample configuration into all the plugins
// It extracts the sample configuration from the plugins README.md
// Then using the file plugin_name_sample_config.go as a template, and will be updated with the sample configuration
// This tool is then also used to revert these changes with the `--clean` flag
package main
import (
"bufio"
"bytes"
"flag"
"fmt"
"log" //nolint:revive
"os"
"strings"
"text/template"
"github.com/yuin/goldmark"
gast "github.com/yuin/goldmark/ast"
"github.com/yuin/goldmark/text"
)
func createSourceName(packageName string) string {
return fmt.Sprintf("%s_sample_config.go", packageName)
}
// extractPluginData reads the README.md to get the sample configuration
func extractPluginData() (string, error) {
readMe, err := os.ReadFile("README.md")
if err != nil {
return "", err
}
p := goldmark.DefaultParser()
r := text.NewReader(readMe)
root := p.Parse(r)
var currentSection string
for n := root.FirstChild(); n != nil; n = n.NextSibling() {
switch tok := n.(type) {
case *gast.Heading:
if tok.FirstChild() != nil {
currentSection = string(tok.FirstChild().Text(readMe))
}
case *gast.FencedCodeBlock:
if currentSection == "Configuration" && string(tok.Language(readMe)) == "toml" {
var config []byte
for i := 0; i < tok.Lines().Len(); i++ {
line := tok.Lines().At(i)
config = append(config, line.Value(readMe)...)
}
return string(config), nil
}
}
}
fmt.Printf("No configuration found for plugin: %s\n", os.Getenv("GOPACKAGE"))
return "", nil
}
// generatePluginData parses the main source file of the plugin as a template and updates it with the sample configuration
// The original source file is saved so that these changes can be reverted
func generatePluginData(packageName string, sampleConfig string) error {
sourceName := createSourceName(packageName)
plugin, err := os.ReadFile(sourceName)
if err != nil {
return err
}
generatedTemplate := template.Must(template.New("").Parse(string(plugin)))
f, err := os.Create(sourceName)
if err != nil {
return err
}
defer f.Close()
err = generatedTemplate.Execute(f, struct {
SampleConfig string
}{
SampleConfig: sampleConfig,
})
if err != nil {
return err
}
return nil
}
var newSampleConfigFunc = ` return ` + "`{{ .SampleConfig }}`\n"
// cleanGeneratedFiles will revert the changes made by generatePluginData
func cleanGeneratedFiles(packageName string) error {
sourceName := createSourceName(packageName)
sourcefile, err := os.Open(sourceName)
if err != nil {
return err
}
defer sourcefile.Close()
var c []byte
buf := bytes.NewBuffer(c)
scanner := bufio.NewScanner(sourcefile)
var sampleconfigSection bool
for scanner.Scan() {
if sampleconfigSection && strings.TrimSpace(scanner.Text()) == "}" {
sampleconfigSection = false
if _, err := buf.Write([]byte(newSampleConfigFunc)); err != nil {
return err
}
}
if !sampleconfigSection {
if _, err := buf.Write(scanner.Bytes()); err != nil {
return err
}
if _, err = buf.WriteString("\n"); err != nil {
return err
}
}
if !sampleconfigSection && strings.Contains(scanner.Text(), "SampleConfig() string") {
sampleconfigSection = true
}
}
err = os.WriteFile(sourceName, buf.Bytes(), 0664)
if err != nil {
return err
}
return nil
}
func main() {
clean := flag.Bool("clean", false, "Remove generated files")
flag.Parse()
goPackage := os.Getenv("GOPACKAGE")
if *clean {
err := cleanGeneratedFiles(goPackage)
if err != nil {
log.Fatal(err)
}
} else {
s, err := extractPluginData()
if err != nil {
log.Fatal(err)
}
err = generatePluginData(goPackage, s)
if err != nil {
log.Fatal(err)
}
}
}

View File

@ -0,0 +1,133 @@
package main
import (
"os"
"testing"
"github.com/stretchr/testify/require"
)
var originalPlugin = `package main
func (*Plugin) SampleConfig() string {
return ` + "`{{ .SampleConfig }}`" + `
}
`
func TestGeneratePluginData(t *testing.T) {
if testing.Short() {
t.Skip("skipping test in short mode.")
}
readme := `# plugin
## Configuration
` + "```" + `toml
# test plugin
[[input.plugin]]
# No configuration
` + "```"
r, err := os.Create("README.md")
require.NoError(t, err)
_, err = r.Write([]byte(readme))
require.NoError(t, err)
err = r.Close()
require.NoError(t, err)
sourceFile, err := os.Create("test_sample_config.go")
require.NoError(t, err)
_, err = sourceFile.Write([]byte(originalPlugin))
require.NoError(t, err)
err = sourceFile.Close()
require.NoError(t, err)
defer func() {
err = os.Remove("test_sample_config.go")
require.NoError(t, err)
err = os.Remove("README.md")
require.NoError(t, err)
}()
s, err := extractPluginData()
require.NoError(t, err)
err = generatePluginData("test", s)
require.NoError(t, err)
expected := `package main
func (*Plugin) SampleConfig() string {
return ` + "`" + `# test plugin
[[input.plugin]]
# No configuration
` + "`" + `
}
`
newSourceFile, err := os.ReadFile("test_sample_config.go")
require.NoError(t, err)
require.Equal(t, expected, string(newSourceFile))
}
func TestGeneratePluginDataNoConfig(t *testing.T) {
if testing.Short() {
t.Skip("skipping test in short mode.")
}
readme := `# plugin`
r, err := os.Create("README.md")
require.NoError(t, err)
_, err = r.Write([]byte(readme))
require.NoError(t, err)
err = r.Close()
require.NoError(t, err)
defer func() {
err = os.Remove("README.md")
require.NoError(t, err)
}()
s, err := extractPluginData()
require.NoError(t, err)
require.Empty(t, s)
}
func setupGeneratedPluginFile(t *testing.T, fileName string) {
// Create files that will be cleaned up
r, err := os.Create(fileName)
require.NoError(t, err)
defer r.Close()
updatePlugin := `package main
func (*Plugin) SampleConfig() string {
return "I am a sample config"
}
`
_, err = r.Write([]byte(updatePlugin))
require.NoError(t, err)
}
func TestCleanGeneratedFiles(t *testing.T) {
if testing.Short() {
t.Skip("skipping test in short mode.")
}
filename := "testClean_sample_config.go"
setupGeneratedPluginFile(t, filename)
err := cleanGeneratedFiles("testClean")
require.NoError(t, err)
b, err := os.ReadFile(filename)
require.NoError(t, err)
require.Equal(t, originalPlugin, string(b))
err = os.Remove(filename)
require.NoError(t, err)
}