github.com/influxdata/telegraf@v1.30.3/cmd/telegraf/printer.go (about)

     1  package main
     2  
     3  import (
     4  	_ "embed"
     5  	"fmt"
     6  	"io"
     7  	"sort"
     8  	"strings"
     9  
    10  	"github.com/influxdata/telegraf"
    11  	"github.com/influxdata/telegraf/internal/choice"
    12  	"github.com/influxdata/telegraf/plugins/aggregators"
    13  	"github.com/influxdata/telegraf/plugins/inputs"
    14  	"github.com/influxdata/telegraf/plugins/outputs"
    15  	"github.com/influxdata/telegraf/plugins/processors"
    16  	"github.com/influxdata/telegraf/plugins/secretstores"
    17  )
    18  
    19  var (
    20  	// Default sections
    21  	sectionDefaults = []string{"global_tags", "agent", "secretstores", "outputs", "processors", "aggregators", "inputs"}
    22  
    23  	// Default input plugins
    24  	inputDefaults = []string{"cpu", "mem", "swap", "system", "kernel", "processes", "disk", "diskio"}
    25  
    26  	// Default output plugins
    27  	outputDefaults = []string{}
    28  )
    29  
    30  var header = `# Telegraf Configuration
    31  #
    32  # Telegraf is entirely plugin driven. All metrics are gathered from the
    33  # declared inputs, and sent to the declared outputs.
    34  #
    35  # Plugins must be declared in here to be active.
    36  # To deactivate a plugin, comment out the name and any variables.
    37  #
    38  # Use 'telegraf -config telegraf.conf -test' to see what metrics a config
    39  # file would generate.
    40  #
    41  # Environment variables can be used anywhere in this config file, simply surround
    42  # them with ${}. For strings the variable must be within quotes (ie, "${STR_VAR}"),
    43  # for numbers and booleans they should be plain (ie, ${INT_VAR}, ${BOOL_VAR})
    44  
    45  `
    46  var globalTagsConfig = `
    47  # Global tags can be specified here in key="value" format.
    48  [global_tags]
    49    # dc = "us-east-1" # will tag all metrics with dc=us-east-1
    50    # rack = "1a"
    51    ## Environment variables can be used as tags, and throughout the config file
    52    # user = "$USER"
    53  
    54  `
    55  
    56  // DO NOT REMOVE THE NEXT TWO LINES! This is required to embed the agentConfig data.
    57  //
    58  //go:embed agent.conf
    59  var agentConfig string
    60  
    61  var secretstoreHeader = `
    62  ###############################################################################
    63  #                            SECRETSTORE PLUGINS                              #
    64  ###############################################################################
    65  
    66  `
    67  
    68  var outputHeader = `
    69  ###############################################################################
    70  #                            OUTPUT PLUGINS                                   #
    71  ###############################################################################
    72  
    73  `
    74  
    75  var processorHeader = `
    76  ###############################################################################
    77  #                            PROCESSOR PLUGINS                                #
    78  ###############################################################################
    79  
    80  `
    81  
    82  var aggregatorHeader = `
    83  ###############################################################################
    84  #                            AGGREGATOR PLUGINS                               #
    85  ###############################################################################
    86  
    87  `
    88  
    89  var inputHeader = `
    90  ###############################################################################
    91  #                            INPUT PLUGINS                                    #
    92  ###############################################################################
    93  
    94  `
    95  
    96  var serviceInputHeader = `
    97  ###############################################################################
    98  #                            SERVICE INPUT PLUGINS                            #
    99  ###############################################################################
   100  
   101  `
   102  
   103  // printSampleConfig prints the sample config
   104  func printSampleConfig(outputBuffer io.Writer, filters Filters) {
   105  	sectionFilters := filters.section
   106  	inputFilters := filters.input
   107  	outputFilters := filters.output
   108  	aggregatorFilters := filters.aggregator
   109  	processorFilters := filters.processor
   110  	secretstoreFilters := filters.secretstore
   111  
   112  	// print headers
   113  	outputBuffer.Write([]byte(header))
   114  
   115  	if len(sectionFilters) == 0 {
   116  		sectionFilters = sectionDefaults
   117  	}
   118  	printFilteredGlobalSections(sectionFilters, outputBuffer)
   119  
   120  	// print secretstore plugins
   121  	if choice.Contains("secretstores", sectionFilters) {
   122  		if len(secretstoreFilters) != 0 {
   123  			if len(secretstoreFilters) >= 3 && secretstoreFilters[1] != "none" {
   124  				fmt.Print(secretstoreHeader)
   125  			}
   126  			printFilteredSecretstores(secretstoreFilters, false, outputBuffer)
   127  		} else {
   128  			fmt.Print(secretstoreHeader)
   129  			snames := []string{}
   130  			for sname := range secretstores.SecretStores {
   131  				snames = append(snames, sname)
   132  			}
   133  			sort.Strings(snames)
   134  			printFilteredSecretstores(snames, true, outputBuffer)
   135  		}
   136  	}
   137  
   138  	// print output plugins
   139  	if choice.Contains("outputs", sectionFilters) {
   140  		if len(outputFilters) != 0 {
   141  			if len(outputFilters) >= 3 && outputFilters[1] != "none" {
   142  				outputBuffer.Write([]byte(outputHeader))
   143  			}
   144  			printFilteredOutputs(outputFilters, false, outputBuffer)
   145  		} else {
   146  			outputBuffer.Write([]byte(outputHeader))
   147  			printFilteredOutputs(outputDefaults, false, outputBuffer)
   148  			// Print non-default outputs, commented
   149  			var pnames []string
   150  			for pname := range outputs.Outputs {
   151  				if !choice.Contains(pname, outputDefaults) {
   152  					pnames = append(pnames, pname)
   153  				}
   154  			}
   155  			printFilteredOutputs(pnames, true, outputBuffer)
   156  		}
   157  	}
   158  
   159  	// print processor plugins
   160  	if choice.Contains("processors", sectionFilters) {
   161  		if len(processorFilters) != 0 {
   162  			if len(processorFilters) >= 3 && processorFilters[1] != "none" {
   163  				outputBuffer.Write([]byte(processorHeader))
   164  			}
   165  			printFilteredProcessors(processorFilters, false, outputBuffer)
   166  		} else {
   167  			outputBuffer.Write([]byte(processorHeader))
   168  			pnames := []string{}
   169  			for pname := range processors.Processors {
   170  				pnames = append(pnames, pname)
   171  			}
   172  			printFilteredProcessors(pnames, true, outputBuffer)
   173  		}
   174  	}
   175  
   176  	// print aggregator plugins
   177  	if choice.Contains("aggregators", sectionFilters) {
   178  		if len(aggregatorFilters) != 0 {
   179  			if len(aggregatorFilters) >= 3 && aggregatorFilters[1] != "none" {
   180  				outputBuffer.Write([]byte(aggregatorHeader))
   181  			}
   182  			printFilteredAggregators(aggregatorFilters, false, outputBuffer)
   183  		} else {
   184  			outputBuffer.Write([]byte(aggregatorHeader))
   185  			pnames := []string{}
   186  			for pname := range aggregators.Aggregators {
   187  				pnames = append(pnames, pname)
   188  			}
   189  			printFilteredAggregators(pnames, true, outputBuffer)
   190  		}
   191  	}
   192  
   193  	// print input plugins
   194  	if choice.Contains("inputs", sectionFilters) {
   195  		if len(inputFilters) != 0 {
   196  			if len(inputFilters) >= 3 && inputFilters[1] != "none" {
   197  				outputBuffer.Write([]byte(inputHeader))
   198  			}
   199  			printFilteredInputs(inputFilters, false, outputBuffer)
   200  		} else {
   201  			outputBuffer.Write([]byte(inputHeader))
   202  			printFilteredInputs(inputDefaults, false, outputBuffer)
   203  			// Print non-default inputs, commented
   204  			var pnames []string
   205  			for pname := range inputs.Inputs {
   206  				if !choice.Contains(pname, inputDefaults) {
   207  					pnames = append(pnames, pname)
   208  				}
   209  			}
   210  			printFilteredInputs(pnames, true, outputBuffer)
   211  		}
   212  	}
   213  }
   214  
   215  func printFilteredProcessors(processorFilters []string, commented bool, outputBuffer io.Writer) {
   216  	// Filter processors
   217  	var pnames []string
   218  	for pname := range processors.Processors {
   219  		if choice.Contains(pname, processorFilters) {
   220  			pnames = append(pnames, pname)
   221  		}
   222  	}
   223  	sort.Strings(pnames)
   224  
   225  	// Print Outputs
   226  	for _, pname := range pnames {
   227  		creator := processors.Processors[pname]
   228  		output := creator()
   229  		printConfig(pname, output, "processors", commented, processors.Deprecations[pname], outputBuffer)
   230  	}
   231  }
   232  
   233  func printFilteredAggregators(aggregatorFilters []string, commented bool, outputBuffer io.Writer) {
   234  	// Filter outputs
   235  	var anames []string
   236  	for aname := range aggregators.Aggregators {
   237  		if choice.Contains(aname, aggregatorFilters) {
   238  			anames = append(anames, aname)
   239  		}
   240  	}
   241  	sort.Strings(anames)
   242  
   243  	// Print Outputs
   244  	for _, aname := range anames {
   245  		creator := aggregators.Aggregators[aname]
   246  		output := creator()
   247  		printConfig(aname, output, "aggregators", commented, aggregators.Deprecations[aname], outputBuffer)
   248  	}
   249  }
   250  
   251  func printFilteredInputs(inputFilters []string, commented bool, outputBuffer io.Writer) {
   252  	// Filter inputs
   253  	var pnames []string
   254  	for pname := range inputs.Inputs {
   255  		if choice.Contains(pname, inputFilters) {
   256  			pnames = append(pnames, pname)
   257  		}
   258  	}
   259  	sort.Strings(pnames)
   260  
   261  	// cache service inputs to print them at the end
   262  	servInputs := make(map[string]telegraf.ServiceInput)
   263  	// for alphabetical looping:
   264  	servInputNames := []string{}
   265  
   266  	// Print Inputs
   267  	for _, pname := range pnames {
   268  		// Skip inputs that are registered twice for backward compatibility
   269  		switch pname {
   270  		case "cisco_telemetry_gnmi", "io", "KNXListener":
   271  			continue
   272  		}
   273  		creator := inputs.Inputs[pname]
   274  		input := creator()
   275  
   276  		if p, ok := input.(telegraf.ServiceInput); ok {
   277  			servInputs[pname] = p
   278  			servInputNames = append(servInputNames, pname)
   279  			continue
   280  		}
   281  
   282  		printConfig(pname, input, "inputs", commented, inputs.Deprecations[pname], outputBuffer)
   283  	}
   284  
   285  	// Print Service Inputs
   286  	if len(servInputs) == 0 {
   287  		return
   288  	}
   289  	sort.Strings(servInputNames)
   290  
   291  	outputBuffer.Write([]byte(serviceInputHeader))
   292  	for _, name := range servInputNames {
   293  		printConfig(name, servInputs[name], "inputs", commented, inputs.Deprecations[name], outputBuffer)
   294  	}
   295  }
   296  
   297  func printFilteredOutputs(outputFilters []string, commented bool, outputBuffer io.Writer) {
   298  	// Filter outputs
   299  	var onames []string
   300  	var influxdbV2 string
   301  
   302  	for oname := range outputs.Outputs {
   303  		if choice.Contains(oname, outputFilters) {
   304  			// Make influxdb_v2 the exception and have it be first in the list
   305  			// Store it and add it later
   306  			if oname == "influxdb_v2" {
   307  				influxdbV2 = oname
   308  				continue
   309  			}
   310  
   311  			onames = append(onames, oname)
   312  		}
   313  	}
   314  	sort.Strings(onames)
   315  
   316  	if influxdbV2 != "" {
   317  		onames = append([]string{influxdbV2}, onames...)
   318  	}
   319  
   320  	// Print Outputs
   321  	for _, oname := range onames {
   322  		creator := outputs.Outputs[oname]
   323  		output := creator()
   324  		printConfig(oname, output, "outputs", commented, outputs.Deprecations[oname], outputBuffer)
   325  	}
   326  }
   327  
   328  func printFilteredSecretstores(secretstoreFilters []string, commented bool, outputBuffer io.Writer) {
   329  	// Filter secretstores
   330  	var snames []string
   331  	for sname := range secretstores.SecretStores {
   332  		if choice.Contains(sname, secretstoreFilters) {
   333  			snames = append(snames, sname)
   334  		}
   335  	}
   336  	sort.Strings(snames)
   337  
   338  	// Print SecretStores
   339  	for _, sname := range snames {
   340  		creator := secretstores.SecretStores[sname]
   341  		store := creator("dummy")
   342  		printConfig(sname, store, "secretstores", commented, secretstores.Deprecations[sname], outputBuffer)
   343  	}
   344  }
   345  
   346  func printFilteredGlobalSections(sectionFilters []string, outputBuffer io.Writer) {
   347  	if choice.Contains("global_tags", sectionFilters) {
   348  		outputBuffer.Write([]byte(globalTagsConfig))
   349  	}
   350  
   351  	if choice.Contains("agent", sectionFilters) {
   352  		outputBuffer.Write([]byte(agentConfig))
   353  	}
   354  }
   355  
   356  func printConfig(name string, p telegraf.PluginDescriber, op string, commented bool, di telegraf.DeprecationInfo, outputBuffer io.Writer) {
   357  	comment := ""
   358  	if commented {
   359  		comment = "# "
   360  	}
   361  
   362  	if di.Since != "" {
   363  		removalNote := ""
   364  		if di.RemovalIn != "" {
   365  			removalNote = " and will be removed in " + di.RemovalIn
   366  		}
   367  		fmt.Fprintf(outputBuffer, "\n%s ## DEPRECATED: The %q plugin is deprecated in version %s%s, %s.",
   368  			comment, name, di.Since, removalNote, di.Notice)
   369  	}
   370  
   371  	sample := p.SampleConfig()
   372  	if sample == "" {
   373  		fmt.Fprintf(outputBuffer, "\n#[[%s.%s]]", op, name)
   374  		fmt.Fprintf(outputBuffer, "\n%s  # no configuration\n\n", comment)
   375  	} else {
   376  		lines := strings.Split(sample, "\n")
   377  		outputBuffer.Write([]byte("\n"))
   378  		for i, line := range lines {
   379  			if i == len(lines)-1 {
   380  				outputBuffer.Write([]byte("\n"))
   381  				continue
   382  			}
   383  			outputBuffer.Write([]byte(strings.TrimRight(comment+line, " ") + "\n"))
   384  		}
   385  	}
   386  }
   387  
   388  // PrintInputConfig prints the config usage of a single input.
   389  func PrintInputConfig(name string, outputBuffer io.Writer) error {
   390  	creator, ok := inputs.Inputs[name]
   391  	if !ok {
   392  		return fmt.Errorf("input %s not found", name)
   393  	}
   394  
   395  	printConfig(name, creator(), "inputs", false, inputs.Deprecations[name], outputBuffer)
   396  	return nil
   397  }
   398  
   399  // PrintOutputConfig prints the config usage of a single output.
   400  func PrintOutputConfig(name string, outputBuffer io.Writer) error {
   401  	creator, ok := outputs.Outputs[name]
   402  	if !ok {
   403  		return fmt.Errorf("output %s not found", name)
   404  	}
   405  
   406  	printConfig(name, creator(), "outputs", false, outputs.Deprecations[name], outputBuffer)
   407  	return nil
   408  }