2015-04-02 00:34:32 +08:00
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
import (
|
2018-11-06 05:34:28 +08:00
|
|
|
"context"
|
|
|
|
|
"errors"
|
2015-04-08 00:24:34 +08:00
|
|
|
"fmt"
|
2022-10-26 18:06:08 +08:00
|
|
|
"log"
|
2015-04-02 00:34:32 +08:00
|
|
|
"os"
|
|
|
|
|
"os/signal"
|
|
|
|
|
"strings"
|
2016-01-17 16:08:02 +08:00
|
|
|
"syscall"
|
2019-06-15 03:06:25 +08:00
|
|
|
"time"
|
2015-04-02 00:34:32 +08:00
|
|
|
|
2022-01-05 23:21:14 +08:00
|
|
|
"github.com/coreos/go-systemd/daemon"
|
2021-12-08 06:56:18 +08:00
|
|
|
"github.com/fatih/color"
|
2021-07-16 00:11:58 +08:00
|
|
|
"github.com/influxdata/tail/watch"
|
2022-10-13 04:23:53 +08:00
|
|
|
"gopkg.in/tomb.v1"
|
|
|
|
|
|
2021-03-19 05:21:30 +08:00
|
|
|
"github.com/influxdata/telegraf"
|
2016-01-28 05:21:36 +08:00
|
|
|
"github.com/influxdata/telegraf/agent"
|
2020-05-05 02:09:10 +08:00
|
|
|
"github.com/influxdata/telegraf/config"
|
2018-05-05 05:16:21 +08:00
|
|
|
"github.com/influxdata/telegraf/internal"
|
2016-10-01 05:37:56 +08:00
|
|
|
"github.com/influxdata/telegraf/logger"
|
2022-08-20 03:38:03 +08:00
|
|
|
"github.com/influxdata/telegraf/plugins/aggregators"
|
2016-03-04 00:09:49 +08:00
|
|
|
"github.com/influxdata/telegraf/plugins/inputs"
|
2016-03-06 20:08:51 +08:00
|
|
|
"github.com/influxdata/telegraf/plugins/outputs"
|
2022-08-20 03:38:03 +08:00
|
|
|
"github.com/influxdata/telegraf/plugins/parsers"
|
|
|
|
|
"github.com/influxdata/telegraf/plugins/processors"
|
2022-12-09 00:53:06 +08:00
|
|
|
"github.com/influxdata/telegraf/plugins/secretstores"
|
2015-04-02 00:34:32 +08:00
|
|
|
)
|
|
|
|
|
|
2022-08-25 10:46:58 +08:00
|
|
|
var stop chan struct{}
|
2021-05-19 05:20:13 +08:00
|
|
|
|
2022-08-25 10:46:58 +08:00
|
|
|
type GlobalFlags struct {
|
|
|
|
|
config []string
|
|
|
|
|
configDir []string
|
|
|
|
|
testWait int
|
|
|
|
|
watchConfig string
|
|
|
|
|
pidFile string
|
|
|
|
|
plugindDir string
|
|
|
|
|
test bool
|
|
|
|
|
debug bool
|
|
|
|
|
once bool
|
|
|
|
|
quiet bool
|
2021-05-19 05:20:13 +08:00
|
|
|
}
|
|
|
|
|
|
2022-08-25 10:46:58 +08:00
|
|
|
type WindowFlags struct {
|
|
|
|
|
service string
|
|
|
|
|
serviceName string
|
|
|
|
|
serviceDisplayName string
|
|
|
|
|
serviceRestartDelay string
|
|
|
|
|
serviceAutoRestart bool
|
|
|
|
|
console bool
|
2021-05-19 05:20:13 +08:00
|
|
|
}
|
|
|
|
|
|
2022-08-25 10:46:58 +08:00
|
|
|
type App interface {
|
|
|
|
|
Init(<-chan error, Filters, GlobalFlags, WindowFlags)
|
|
|
|
|
Run() error
|
2022-12-09 00:53:06 +08:00
|
|
|
|
|
|
|
|
// Secret store commands
|
|
|
|
|
ListSecretStores() ([]string, error)
|
|
|
|
|
GetSecretStore(string) (telegraf.SecretStore, error)
|
2022-08-25 10:46:58 +08:00
|
|
|
}
|
2016-01-08 06:21:10 +08:00
|
|
|
|
2022-08-25 10:46:58 +08:00
|
|
|
type Telegraf struct {
|
|
|
|
|
pprofErr <-chan error
|
|
|
|
|
|
2022-12-09 00:53:06 +08:00
|
|
|
inputFilters []string
|
|
|
|
|
outputFilters []string
|
|
|
|
|
configFiles []string
|
|
|
|
|
secretstoreFilters []string
|
2022-08-25 10:46:58 +08:00
|
|
|
|
|
|
|
|
GlobalFlags
|
|
|
|
|
WindowFlags
|
|
|
|
|
}
|
2016-07-16 05:00:16 +08:00
|
|
|
|
2022-08-30 05:54:44 +08:00
|
|
|
func (t *Telegraf) Init(pprofErr <-chan error, f Filters, g GlobalFlags, w WindowFlags) {
|
|
|
|
|
t.pprofErr = pprofErr
|
|
|
|
|
t.inputFilters = f.input
|
|
|
|
|
t.outputFilters = f.output
|
2022-12-09 00:53:06 +08:00
|
|
|
t.secretstoreFilters = f.secretstore
|
2022-08-30 05:54:44 +08:00
|
|
|
t.GlobalFlags = g
|
|
|
|
|
t.WindowFlags = w
|
2022-08-25 10:46:58 +08:00
|
|
|
}
|
|
|
|
|
|
2022-12-09 00:53:06 +08:00
|
|
|
func (t *Telegraf) ListSecretStores() ([]string, error) {
|
|
|
|
|
c, err := t.loadConfiguration()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ids := make([]string, 0, len(c.SecretStores))
|
|
|
|
|
for k := range c.SecretStores {
|
|
|
|
|
ids = append(ids, k)
|
|
|
|
|
}
|
|
|
|
|
return ids, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (t *Telegraf) GetSecretStore(id string) (telegraf.SecretStore, error) {
|
|
|
|
|
c, err := t.loadConfiguration()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
store, found := c.SecretStores[id]
|
|
|
|
|
if !found {
|
|
|
|
|
return nil, errors.New("unknown secret store")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return store, nil
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-30 05:54:44 +08:00
|
|
|
func (t *Telegraf) reloadLoop() error {
|
2023-02-06 17:05:59 +08:00
|
|
|
cfg, err := t.loadConfiguration()
|
2023-01-04 17:40:39 +08:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-17 16:08:02 +08:00
|
|
|
reload := make(chan bool, 1)
|
|
|
|
|
reload <- true
|
|
|
|
|
for <-reload {
|
|
|
|
|
reload <- false
|
2018-11-06 05:34:28 +08:00
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
2015-04-07 08:24:24 +08:00
|
|
|
|
2020-04-21 01:49:10 +08:00
|
|
|
signals := make(chan os.Signal, 1)
|
2018-11-16 07:44:36 +08:00
|
|
|
signal.Notify(signals, os.Interrupt, syscall.SIGHUP,
|
|
|
|
|
syscall.SIGTERM, syscall.SIGINT)
|
2022-08-30 05:54:44 +08:00
|
|
|
if t.watchConfig != "" {
|
2022-11-08 03:54:52 +08:00
|
|
|
for _, fConfig := range t.configFiles {
|
2021-07-16 00:11:58 +08:00
|
|
|
if _, err := os.Stat(fConfig); err == nil {
|
2022-08-30 05:54:44 +08:00
|
|
|
go t.watchLocalConfig(signals, fConfig)
|
2021-07-16 00:11:58 +08:00
|
|
|
} else {
|
|
|
|
|
log.Printf("W! Cannot watch config %s: %s", fConfig, err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-01-17 16:08:02 +08:00
|
|
|
go func() {
|
2016-07-16 05:00:16 +08:00
|
|
|
select {
|
|
|
|
|
case sig := <-signals:
|
2016-08-08 22:55:16 +08:00
|
|
|
if sig == syscall.SIGHUP {
|
2018-11-06 05:34:28 +08:00
|
|
|
log.Printf("I! Reloading Telegraf config")
|
2016-08-08 22:55:16 +08:00
|
|
|
<-reload
|
|
|
|
|
reload <- true
|
2016-07-16 05:00:16 +08:00
|
|
|
}
|
2018-11-06 05:34:28 +08:00
|
|
|
cancel()
|
2022-08-30 05:54:44 +08:00
|
|
|
case err := <-t.pprofErr:
|
2022-08-25 10:46:58 +08:00
|
|
|
log.Printf("E! pprof server failed: %v", err)
|
|
|
|
|
cancel()
|
2016-07-16 05:00:16 +08:00
|
|
|
case <-stop:
|
2018-11-06 05:34:28 +08:00
|
|
|
cancel()
|
2016-01-17 16:08:02 +08:00
|
|
|
}
|
|
|
|
|
}()
|
2015-04-07 08:24:24 +08:00
|
|
|
|
2023-02-06 17:05:59 +08:00
|
|
|
err := t.runAgent(ctx, cfg)
|
2019-06-01 07:50:44 +08:00
|
|
|
if err != nil && err != context.Canceled {
|
2022-08-25 10:46:58 +08:00
|
|
|
return fmt.Errorf("[telegraf] Error running agent: %v", err)
|
2018-11-06 05:34:28 +08:00
|
|
|
}
|
|
|
|
|
}
|
2022-08-25 10:46:58 +08:00
|
|
|
|
|
|
|
|
return nil
|
2018-11-06 05:34:28 +08:00
|
|
|
}
|
|
|
|
|
|
2022-08-30 05:54:44 +08:00
|
|
|
func (t *Telegraf) watchLocalConfig(signals chan os.Signal, fConfig string) {
|
2021-07-16 00:11:58 +08:00
|
|
|
var mytomb tomb.Tomb
|
|
|
|
|
var watcher watch.FileWatcher
|
2022-08-30 05:54:44 +08:00
|
|
|
if t.watchConfig == "poll" {
|
2021-07-16 00:11:58 +08:00
|
|
|
watcher = watch.NewPollingFileWatcher(fConfig)
|
|
|
|
|
} else {
|
|
|
|
|
watcher = watch.NewInotifyFileWatcher(fConfig)
|
|
|
|
|
}
|
|
|
|
|
changes, err := watcher.ChangeEvents(&mytomb, 0)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Printf("E! Error watching config: %s\n", err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
log.Println("I! Config watcher started")
|
|
|
|
|
select {
|
|
|
|
|
case <-changes.Modified:
|
|
|
|
|
log.Println("I! Config file modified")
|
|
|
|
|
case <-changes.Deleted:
|
|
|
|
|
// deleted can mean moved. wait a bit a check existence
|
|
|
|
|
<-time.After(time.Second)
|
|
|
|
|
if _, err := os.Stat(fConfig); err == nil {
|
|
|
|
|
log.Println("I! Config file overwritten")
|
|
|
|
|
} else {
|
|
|
|
|
log.Println("W! Config file deleted")
|
|
|
|
|
if err := watcher.BlockUntilExists(&mytomb); err != nil {
|
|
|
|
|
log.Printf("E! Cannot watch for config: %s\n", err.Error())
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
log.Println("I! Config file appeared")
|
|
|
|
|
}
|
|
|
|
|
case <-changes.Truncated:
|
|
|
|
|
log.Println("I! Config file truncated")
|
|
|
|
|
case <-mytomb.Dying():
|
|
|
|
|
log.Println("I! Config watcher ended")
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
mytomb.Done()
|
|
|
|
|
signals <- syscall.SIGHUP
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-09 00:53:06 +08:00
|
|
|
func (t *Telegraf) loadConfiguration() (*config.Config, error) {
|
|
|
|
|
// If no other options are specified, load the config file and run.
|
|
|
|
|
c := config.NewConfig()
|
|
|
|
|
c.OutputFilters = t.outputFilters
|
|
|
|
|
c.InputFilters = t.inputFilters
|
|
|
|
|
c.SecretStoreFilters = t.secretstoreFilters
|
|
|
|
|
|
2022-11-08 03:54:52 +08:00
|
|
|
var configFiles []string
|
2018-11-06 05:34:28 +08:00
|
|
|
|
2023-02-08 00:02:01 +08:00
|
|
|
configFiles = append(configFiles, t.config...)
|
2022-08-30 05:54:44 +08:00
|
|
|
for _, fConfigDirectory := range t.configDir {
|
2022-11-08 03:54:52 +08:00
|
|
|
files, err := config.WalkDirectory(fConfigDirectory)
|
2018-11-06 05:34:28 +08:00
|
|
|
if err != nil {
|
2022-12-09 00:53:06 +08:00
|
|
|
return c, err
|
2016-01-17 16:08:02 +08:00
|
|
|
}
|
2022-11-08 03:54:52 +08:00
|
|
|
configFiles = append(configFiles, files...)
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-08 00:02:01 +08:00
|
|
|
// providing no "config" or "config-directory" flag(s) should load default
|
|
|
|
|
// configuration files
|
|
|
|
|
if len(configFiles) == 0 {
|
|
|
|
|
configFiles = append(configFiles, "")
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-08 03:54:52 +08:00
|
|
|
t.configFiles = configFiles
|
|
|
|
|
if err := c.LoadAll(configFiles...); err != nil {
|
2022-12-09 00:53:06 +08:00
|
|
|
return c, err
|
|
|
|
|
}
|
|
|
|
|
return c, nil
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-06 17:05:59 +08:00
|
|
|
func (t *Telegraf) runAgent(ctx context.Context, c *config.Config) error {
|
2022-08-30 05:54:44 +08:00
|
|
|
if !(t.test || t.testWait != 0) && len(c.Outputs) == 0 {
|
2022-10-13 04:23:53 +08:00
|
|
|
return errors.New("no outputs found, did you provide a valid config file?")
|
2018-11-06 05:34:28 +08:00
|
|
|
}
|
2022-08-30 05:54:44 +08:00
|
|
|
if t.plugindDir == "" && len(c.Inputs) == 0 {
|
2022-10-13 04:23:53 +08:00
|
|
|
return errors.New("no inputs found, did you provide a valid config file?")
|
2018-11-06 05:34:28 +08:00
|
|
|
}
|
|
|
|
|
|
2021-04-10 01:15:04 +08:00
|
|
|
if int64(c.Agent.Interval) <= 0 {
|
2022-10-13 04:23:53 +08:00
|
|
|
return fmt.Errorf("agent interval must be positive, found %v", c.Agent.Interval)
|
2018-11-06 05:34:28 +08:00
|
|
|
}
|
|
|
|
|
|
2021-04-10 01:15:04 +08:00
|
|
|
if int64(c.Agent.FlushInterval) <= 0 {
|
2022-10-13 04:23:53 +08:00
|
|
|
return fmt.Errorf("agent flush_interval must be positive; found %v", c.Agent.Interval)
|
2018-11-06 05:34:28 +08:00
|
|
|
}
|
2016-01-17 16:08:02 +08:00
|
|
|
|
2018-11-16 07:45:56 +08:00
|
|
|
// Setup logging as configured.
|
2022-08-30 05:54:44 +08:00
|
|
|
telegraf.Debug = c.Agent.Debug || t.debug
|
2019-05-04 01:25:28 +08:00
|
|
|
logConfig := logger.LogConfig{
|
2021-03-19 05:21:30 +08:00
|
|
|
Debug: telegraf.Debug,
|
2022-08-30 05:54:44 +08:00
|
|
|
Quiet: c.Agent.Quiet || t.quiet,
|
2022-02-01 04:30:52 +08:00
|
|
|
LogTarget: c.Agent.LogTarget,
|
|
|
|
|
Logfile: c.Agent.Logfile,
|
|
|
|
|
RotationInterval: c.Agent.LogfileRotationInterval,
|
|
|
|
|
RotationMaxSize: c.Agent.LogfileRotationMaxSize,
|
|
|
|
|
RotationMaxArchives: c.Agent.LogfileRotationMaxArchives,
|
|
|
|
|
LogWithTimezone: c.Agent.LogWithTimezone,
|
2019-05-04 01:25:28 +08:00
|
|
|
}
|
|
|
|
|
|
2022-12-09 00:53:06 +08:00
|
|
|
if err := logger.SetupLogging(logConfig); err != nil {
|
2022-10-13 04:23:53 +08:00
|
|
|
return err
|
|
|
|
|
}
|
2018-11-06 05:34:28 +08:00
|
|
|
|
2022-08-25 10:46:58 +08:00
|
|
|
log.Printf("I! Starting Telegraf %s%s", internal.Version, internal.Customized)
|
2022-12-09 00:53:06 +08:00
|
|
|
log.Printf("I! Available plugins: %d inputs, %d aggregators, %d processors, %d parsers, %d outputs, %d secret-stores",
|
2022-08-20 03:38:03 +08:00
|
|
|
len(inputs.Inputs),
|
|
|
|
|
len(aggregators.Aggregators),
|
|
|
|
|
len(processors.Processors),
|
|
|
|
|
len(parsers.Parsers),
|
|
|
|
|
len(outputs.Outputs),
|
2022-12-09 00:53:06 +08:00
|
|
|
len(secretstores.SecretStores),
|
2022-08-20 03:38:03 +08:00
|
|
|
)
|
2018-11-06 05:34:28 +08:00
|
|
|
log.Printf("I! Loaded inputs: %s", strings.Join(c.InputNames(), " "))
|
|
|
|
|
log.Printf("I! Loaded aggregators: %s", strings.Join(c.AggregatorNames(), " "))
|
|
|
|
|
log.Printf("I! Loaded processors: %s", strings.Join(c.ProcessorNames(), " "))
|
2022-12-09 00:53:06 +08:00
|
|
|
log.Printf("I! Loaded secretstores: %s", strings.Join(c.SecretstoreNames(), " "))
|
2022-08-30 05:54:44 +08:00
|
|
|
if !t.once && (t.test || t.testWait != 0) {
|
2021-12-22 22:05:05 +08:00
|
|
|
log.Print("W! " + color.RedString("Outputs are not used in testing mode!"))
|
2021-12-08 06:56:18 +08:00
|
|
|
} else {
|
|
|
|
|
log.Printf("I! Loaded outputs: %s", strings.Join(c.OutputNames(), " "))
|
|
|
|
|
}
|
2018-11-06 05:34:28 +08:00
|
|
|
log.Printf("I! Tags enabled: %s", c.ListTags())
|
|
|
|
|
|
2021-12-02 03:38:43 +08:00
|
|
|
if count, found := c.Deprecations["inputs"]; found && (count[0] > 0 || count[1] > 0) {
|
|
|
|
|
log.Printf("W! Deprecated inputs: %d and %d options", count[0], count[1])
|
|
|
|
|
}
|
|
|
|
|
if count, found := c.Deprecations["aggregators"]; found && (count[0] > 0 || count[1] > 0) {
|
|
|
|
|
log.Printf("W! Deprecated aggregators: %d and %d options", count[0], count[1])
|
|
|
|
|
}
|
|
|
|
|
if count, found := c.Deprecations["processors"]; found && (count[0] > 0 || count[1] > 0) {
|
|
|
|
|
log.Printf("W! Deprecated processors: %d and %d options", count[0], count[1])
|
|
|
|
|
}
|
|
|
|
|
if count, found := c.Deprecations["outputs"]; found && (count[0] > 0 || count[1] > 0) {
|
|
|
|
|
log.Printf("W! Deprecated outputs: %d and %d options", count[0], count[1])
|
|
|
|
|
}
|
2022-12-09 00:53:06 +08:00
|
|
|
if count, found := c.Deprecations["secretstores"]; found && (count[0] > 0 || count[1] > 0) {
|
|
|
|
|
log.Printf("W! Deprecated secretstores: %d and %d options", count[0], count[1])
|
|
|
|
|
}
|
2021-12-02 03:38:43 +08:00
|
|
|
|
2022-11-09 03:04:12 +08:00
|
|
|
ag := agent.NewAgent(c)
|
2022-02-01 04:30:52 +08:00
|
|
|
|
2022-01-05 23:21:14 +08:00
|
|
|
// Notify systemd that telegraf is ready
|
|
|
|
|
// SdNotify() only tries to notify if the NOTIFY_SOCKET environment is set, so it's safe to call when systemd isn't present.
|
|
|
|
|
// Ignore the return values here because they're not valid for platforms that don't use systemd.
|
|
|
|
|
// For platforms that use systemd, telegraf doesn't log if the notification failed.
|
|
|
|
|
_, _ = daemon.SdNotify(false, daemon.SdNotifyReady)
|
|
|
|
|
|
2022-08-30 05:54:44 +08:00
|
|
|
if t.once {
|
|
|
|
|
wait := time.Duration(t.testWait) * time.Second
|
2021-12-08 06:56:18 +08:00
|
|
|
return ag.Once(ctx, wait)
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-30 05:54:44 +08:00
|
|
|
if t.test || t.testWait != 0 {
|
|
|
|
|
wait := time.Duration(t.testWait) * time.Second
|
2021-12-08 06:56:18 +08:00
|
|
|
return ag.Test(ctx, wait)
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-30 05:54:44 +08:00
|
|
|
if t.pidFile != "" {
|
|
|
|
|
f, err := os.OpenFile(t.pidFile, os.O_CREATE|os.O_WRONLY, 0644)
|
2018-11-06 05:34:28 +08:00
|
|
|
if err != nil {
|
|
|
|
|
log.Printf("E! Unable to create pidfile: %s", err)
|
|
|
|
|
} else {
|
2022-10-12 00:31:44 +08:00
|
|
|
fmt.Fprintf(f, "%d\n", os.Getpid())
|
2018-11-06 05:34:28 +08:00
|
|
|
|
2022-08-25 10:46:58 +08:00
|
|
|
err = f.Close()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2018-11-06 05:34:28 +08:00
|
|
|
|
|
|
|
|
defer func() {
|
2022-08-30 05:54:44 +08:00
|
|
|
err := os.Remove(t.pidFile)
|
2018-11-06 05:34:28 +08:00
|
|
|
if err != nil {
|
|
|
|
|
log.Printf("E! Unable to remove pidfile: %s", err)
|
|
|
|
|
}
|
|
|
|
|
}()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ag.Run(ctx)
|
2015-04-02 00:34:32 +08:00
|
|
|
}
|