2015-09-11 14:37:13 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2018-03-14 12:14:03 +00:00
|
|
|
"context"
|
2016-05-03 14:52:14 +00:00
|
|
|
"encoding/json"
|
2016-07-21 14:33:49 +00:00
|
|
|
fmtlog "log"
|
2017-08-21 21:18:02 +00:00
|
|
|
"net/http"
|
2016-07-21 14:33:49 +00:00
|
|
|
"os"
|
2017-04-27 15:36:04 +00:00
|
|
|
"path/filepath"
|
2016-07-21 14:33:49 +00:00
|
|
|
"reflect"
|
|
|
|
"strings"
|
2016-10-27 14:17:02 +00:00
|
|
|
"time"
|
2016-07-21 14:33:49 +00:00
|
|
|
|
2017-10-16 16:06:04 +00:00
|
|
|
"github.com/cenk/backoff"
|
2016-05-03 14:52:14 +00:00
|
|
|
"github.com/containous/flaeg"
|
|
|
|
"github.com/containous/staert"
|
2018-03-01 07:10:04 +00:00
|
|
|
"github.com/containous/traefik/cmd"
|
|
|
|
"github.com/containous/traefik/cmd/bug"
|
|
|
|
"github.com/containous/traefik/cmd/healthcheck"
|
|
|
|
"github.com/containous/traefik/cmd/storeconfig"
|
|
|
|
cmdVersion "github.com/containous/traefik/cmd/version"
|
2017-11-25 12:36:03 +00:00
|
|
|
"github.com/containous/traefik/collector"
|
2017-08-25 14:10:03 +00:00
|
|
|
"github.com/containous/traefik/configuration"
|
2018-04-23 13:30:03 +00:00
|
|
|
"github.com/containous/traefik/configuration/router"
|
2017-10-16 16:06:04 +00:00
|
|
|
"github.com/containous/traefik/job"
|
2016-08-18 12:20:11 +00:00
|
|
|
"github.com/containous/traefik/log"
|
2018-03-05 19:54:04 +00:00
|
|
|
"github.com/containous/traefik/provider/acme"
|
2017-08-22 09:46:03 +00:00
|
|
|
"github.com/containous/traefik/provider/ecs"
|
2017-04-17 10:50:02 +00:00
|
|
|
"github.com/containous/traefik/provider/kubernetes"
|
2016-10-27 14:17:02 +00:00
|
|
|
"github.com/containous/traefik/safe"
|
2017-04-17 20:47:53 +00:00
|
|
|
"github.com/containous/traefik/server"
|
2017-10-02 08:32:02 +00:00
|
|
|
"github.com/containous/traefik/server/uuid"
|
2018-03-06 09:12:04 +00:00
|
|
|
traefiktls "github.com/containous/traefik/tls"
|
2016-05-31 07:54:42 +00:00
|
|
|
"github.com/containous/traefik/types"
|
2016-07-21 14:33:49 +00:00
|
|
|
"github.com/containous/traefik/version"
|
2016-10-27 14:17:02 +00:00
|
|
|
"github.com/coreos/go-systemd/daemon"
|
2018-02-05 08:12:03 +00:00
|
|
|
"github.com/ogier/pflag"
|
2018-01-22 11:16:03 +00:00
|
|
|
"github.com/sirupsen/logrus"
|
2018-04-11 14:30:04 +00:00
|
|
|
"github.com/vulcand/oxy/roundrobin"
|
2015-09-11 23:55:10 +00:00
|
|
|
)
|
2015-09-11 14:37:13 +00:00
|
|
|
|
|
|
|
func main() {
|
2018-02-19 00:04:45 +00:00
|
|
|
// traefik config inits
|
2018-03-01 07:10:04 +00:00
|
|
|
traefikConfiguration := cmd.NewTraefikConfiguration()
|
|
|
|
traefikPointersConfiguration := cmd.NewTraefikDefaultPointersConfiguration()
|
2018-02-19 00:04:45 +00:00
|
|
|
|
|
|
|
// traefik Command init
|
2016-05-03 14:52:14 +00:00
|
|
|
traefikCmd := &flaeg.Command{
|
|
|
|
Name: "traefik",
|
|
|
|
Description: `traefik is a modern HTTP reverse proxy and load balancer made to deploy microservices with ease.
|
|
|
|
Complete documentation is available at https://traefik.io`,
|
|
|
|
Config: traefikConfiguration,
|
|
|
|
DefaultPointersConfig: traefikPointersConfiguration,
|
|
|
|
Run: func() error {
|
2018-03-01 07:10:04 +00:00
|
|
|
runCmd(&traefikConfiguration.GlobalConfiguration, traefikConfiguration.ConfigFile)
|
2016-05-03 14:52:14 +00:00
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2018-02-19 00:04:45 +00:00
|
|
|
// storeconfig Command init
|
2018-03-01 07:10:04 +00:00
|
|
|
storeConfigCmd := storeconfig.NewCmd(traefikConfiguration, traefikPointersConfiguration)
|
2017-08-21 21:18:02 +00:00
|
|
|
|
2018-02-19 00:04:45 +00:00
|
|
|
// init flaeg source
|
2016-05-03 14:52:14 +00:00
|
|
|
f := flaeg.New(traefikCmd, os.Args[1:])
|
2018-02-19 00:04:45 +00:00
|
|
|
// add custom parsers
|
2017-08-25 14:10:03 +00:00
|
|
|
f.AddParser(reflect.TypeOf(configuration.EntryPoints{}), &configuration.EntryPoints{})
|
|
|
|
f.AddParser(reflect.TypeOf(configuration.DefaultEntryPoints{}), &configuration.DefaultEntryPoints{})
|
2018-03-06 09:12:04 +00:00
|
|
|
f.AddParser(reflect.TypeOf(traefiktls.RootCAs{}), &traefiktls.RootCAs{})
|
2016-06-02 13:17:04 +00:00
|
|
|
f.AddParser(reflect.TypeOf(types.Constraints{}), &types.Constraints{})
|
2017-04-17 10:50:02 +00:00
|
|
|
f.AddParser(reflect.TypeOf(kubernetes.Namespaces{}), &kubernetes.Namespaces{})
|
2017-08-22 09:46:03 +00:00
|
|
|
f.AddParser(reflect.TypeOf(ecs.Clusters{}), &ecs.Clusters{})
|
2018-03-05 19:54:04 +00:00
|
|
|
f.AddParser(reflect.TypeOf([]types.Domain{}), &types.Domains{})
|
2017-01-12 13:34:54 +00:00
|
|
|
f.AddParser(reflect.TypeOf(types.Buckets{}), &types.Buckets{})
|
2018-03-14 13:12:04 +00:00
|
|
|
f.AddParser(reflect.TypeOf(types.StatusCodes{}), &types.StatusCodes{})
|
|
|
|
f.AddParser(reflect.TypeOf(types.FieldNames{}), &types.FieldNames{})
|
|
|
|
f.AddParser(reflect.TypeOf(types.FieldHeaderNames{}), &types.FieldHeaderNames{})
|
2016-05-25 15:06:34 +00:00
|
|
|
|
2018-02-19 00:04:45 +00:00
|
|
|
// add commands
|
2018-03-01 07:10:04 +00:00
|
|
|
f.AddCommand(cmdVersion.NewCmd())
|
|
|
|
f.AddCommand(bug.NewCmd(traefikConfiguration, traefikPointersConfiguration))
|
2017-08-25 14:10:03 +00:00
|
|
|
f.AddCommand(storeConfigCmd)
|
2018-03-01 07:10:04 +00:00
|
|
|
f.AddCommand(healthcheck.NewCmd(traefikConfiguration, traefikPointersConfiguration))
|
2016-07-29 15:36:53 +00:00
|
|
|
|
|
|
|
usedCmd, err := f.GetCommand()
|
|
|
|
if err != nil {
|
|
|
|
fmtlog.Println(err)
|
2018-02-19 00:05:39 +00:00
|
|
|
os.Exit(1)
|
2016-07-29 15:36:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if _, err := f.Parse(usedCmd); err != nil {
|
2018-02-05 08:12:03 +00:00
|
|
|
if err == pflag.ErrHelp {
|
|
|
|
os.Exit(0)
|
|
|
|
}
|
2016-09-23 16:27:01 +00:00
|
|
|
fmtlog.Printf("Error parsing command: %s\n", err)
|
2018-02-19 00:05:39 +00:00
|
|
|
os.Exit(1)
|
2016-05-24 12:58:25 +00:00
|
|
|
}
|
|
|
|
|
2018-02-19 00:04:45 +00:00
|
|
|
// staert init
|
2016-05-24 12:58:25 +00:00
|
|
|
s := staert.NewStaert(traefikCmd)
|
2018-02-19 00:04:45 +00:00
|
|
|
// init TOML source
|
2016-05-24 12:58:25 +00:00
|
|
|
toml := staert.NewTomlSource("traefik", []string{traefikConfiguration.ConfigFile, "/etc/traefik/", "$HOME/.traefik/", "."})
|
2016-05-03 14:52:14 +00:00
|
|
|
|
2018-02-19 00:04:45 +00:00
|
|
|
// add sources to staert
|
2016-05-03 14:52:14 +00:00
|
|
|
s.AddSource(toml)
|
|
|
|
s.AddSource(f)
|
2016-05-27 08:04:56 +00:00
|
|
|
if _, err := s.LoadConfig(); err != nil {
|
2017-10-02 08:32:02 +00:00
|
|
|
fmtlog.Printf("Error reading TOML config file %s : %s\n", toml.ConfigFileUsed(), err)
|
2018-02-19 00:05:39 +00:00
|
|
|
os.Exit(1)
|
2016-05-24 12:58:25 +00:00
|
|
|
}
|
2016-05-30 09:37:12 +00:00
|
|
|
|
|
|
|
traefikConfiguration.ConfigFile = toml.ConfigFileUsed()
|
|
|
|
|
2018-03-01 07:10:04 +00:00
|
|
|
kv, err := storeconfig.CreateKvSource(traefikConfiguration)
|
2016-06-24 07:58:42 +00:00
|
|
|
if err != nil {
|
2016-09-23 16:27:01 +00:00
|
|
|
fmtlog.Printf("Error creating kv store: %s\n", err)
|
2018-02-19 00:05:39 +00:00
|
|
|
os.Exit(1)
|
2016-06-24 07:58:42 +00:00
|
|
|
}
|
2018-03-01 07:10:04 +00:00
|
|
|
storeConfigCmd.Run = storeconfig.Run(kv, traefikConfiguration)
|
2016-06-24 07:58:42 +00:00
|
|
|
|
2018-02-19 00:04:45 +00:00
|
|
|
// if a KV Store is enable and no sub-command called in args
|
2016-07-20 09:48:39 +00:00
|
|
|
if kv != nil && usedCmd == traefikCmd {
|
2016-08-16 17:13:18 +00:00
|
|
|
if traefikConfiguration.Cluster == nil {
|
2017-10-02 08:32:02 +00:00
|
|
|
traefikConfiguration.Cluster = &types.Cluster{Node: uuid.Get()}
|
2016-08-18 11:03:10 +00:00
|
|
|
}
|
|
|
|
if traefikConfiguration.Cluster.Store == nil {
|
|
|
|
traefikConfiguration.Cluster.Store = &types.Store{Prefix: kv.Prefix, Store: kv.Store}
|
2016-08-16 17:13:18 +00:00
|
|
|
}
|
2016-06-24 07:58:42 +00:00
|
|
|
s.AddSource(kv)
|
2017-10-16 16:06:04 +00:00
|
|
|
operation := func() error {
|
|
|
|
_, err := s.LoadConfig()
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
notify := func(err error, time time.Duration) {
|
|
|
|
log.Errorf("Load config error: %+v, retrying in %s", err, time)
|
|
|
|
}
|
|
|
|
err := backoff.RetryNotify(safe.OperationWithRecover(operation), job.NewBackOff(backoff.NewExponentialBackOff()), notify)
|
|
|
|
if err != nil {
|
2016-09-23 16:27:01 +00:00
|
|
|
fmtlog.Printf("Error loading configuration: %s\n", err)
|
2018-02-19 00:05:39 +00:00
|
|
|
os.Exit(1)
|
2016-06-24 07:58:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-03 14:52:14 +00:00
|
|
|
if err := s.Run(); err != nil {
|
2016-09-23 16:27:01 +00:00
|
|
|
fmtlog.Printf("Error running traefik: %s\n", err)
|
2018-02-19 00:05:39 +00:00
|
|
|
os.Exit(1)
|
2015-11-23 14:41:16 +00:00
|
|
|
}
|
2016-05-03 14:52:14 +00:00
|
|
|
|
2016-01-13 21:46:44 +00:00
|
|
|
os.Exit(0)
|
2015-09-11 14:37:13 +00:00
|
|
|
}
|
2016-05-03 14:52:14 +00:00
|
|
|
|
2018-03-01 07:10:04 +00:00
|
|
|
func runCmd(globalConfiguration *configuration.GlobalConfiguration, configFile string) {
|
2017-10-11 08:38:03 +00:00
|
|
|
configureLogging(globalConfiguration)
|
|
|
|
|
|
|
|
if len(configFile) > 0 {
|
|
|
|
log.Infof("Using TOML configuration file %s", configFile)
|
|
|
|
}
|
2016-05-03 14:52:14 +00:00
|
|
|
|
2017-08-25 14:10:03 +00:00
|
|
|
http.DefaultTransport.(*http.Transport).Proxy = http.ProxyFromEnvironment
|
2016-05-30 09:37:12 +00:00
|
|
|
|
2018-04-11 14:30:04 +00:00
|
|
|
if globalConfiguration.AllowMinWeightZero {
|
|
|
|
roundrobin.SetDefaultWeight(0)
|
|
|
|
}
|
|
|
|
|
2017-10-11 08:38:03 +00:00
|
|
|
globalConfiguration.SetEffectiveConfiguration(configFile)
|
2018-01-25 11:02:04 +00:00
|
|
|
globalConfiguration.ValidateConfiguration()
|
2017-10-11 08:38:03 +00:00
|
|
|
|
|
|
|
jsonConf, _ := json.Marshal(globalConfiguration)
|
|
|
|
log.Infof("Traefik version %s built on %s", version.Version, version.BuildDate)
|
|
|
|
|
|
|
|
if globalConfiguration.CheckNewVersion {
|
|
|
|
checkNewVersion()
|
|
|
|
}
|
|
|
|
|
2017-11-25 12:36:03 +00:00
|
|
|
stats(globalConfiguration)
|
|
|
|
|
2017-10-11 08:38:03 +00:00
|
|
|
log.Debugf("Global configuration loaded %s", string(jsonConf))
|
2018-03-05 19:54:04 +00:00
|
|
|
if acme.IsEnabled() {
|
|
|
|
store := acme.NewLocalStore(acme.Get().Storage)
|
|
|
|
acme.Get().Store = &store
|
|
|
|
}
|
2018-04-23 13:30:03 +00:00
|
|
|
|
|
|
|
entryPoints := map[string]server.EntryPoint{}
|
|
|
|
for entryPointName, config := range globalConfiguration.EntryPoints {
|
|
|
|
internalRouter := router.NewInternalRouterAggregator(*globalConfiguration, entryPointName)
|
|
|
|
if acme.IsEnabled() && acme.Get().HTTPChallenge != nil && acme.Get().HTTPChallenge.EntryPoint == entryPointName {
|
|
|
|
internalRouter.AddRouter(acme.Get())
|
|
|
|
}
|
|
|
|
|
|
|
|
entryPoints[entryPointName] = server.EntryPoint{
|
|
|
|
InternalRouter: internalRouter,
|
|
|
|
Configuration: config,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
svr := server.NewServer(*globalConfiguration, configuration.NewProviderAggregator(globalConfiguration), entryPoints)
|
2018-03-05 19:54:04 +00:00
|
|
|
if acme.IsEnabled() && acme.Get().OnHostRule {
|
|
|
|
acme.Get().SetConfigListenerChan(make(chan types.Configuration))
|
|
|
|
svr.AddListener(acme.Get().ListenConfiguration)
|
|
|
|
}
|
2018-03-14 12:14:03 +00:00
|
|
|
ctx := cmd.ContextWithSignal(context.Background())
|
2018-04-23 13:30:03 +00:00
|
|
|
|
|
|
|
if globalConfiguration.Ping != nil {
|
|
|
|
globalConfiguration.Ping.WithContext(ctx)
|
|
|
|
}
|
|
|
|
|
2018-03-14 12:14:03 +00:00
|
|
|
svr.StartWithContext(ctx)
|
2017-10-11 08:38:03 +00:00
|
|
|
defer svr.Close()
|
2017-11-23 15:10:04 +00:00
|
|
|
|
2017-10-11 08:38:03 +00:00
|
|
|
sent, err := daemon.SdNotify(false, "READY=1")
|
|
|
|
if !sent && err != nil {
|
|
|
|
log.Error("Fail to notify", err)
|
|
|
|
}
|
2017-11-23 15:10:04 +00:00
|
|
|
|
2017-10-11 08:38:03 +00:00
|
|
|
t, err := daemon.SdWatchdogEnabled(false)
|
|
|
|
if err != nil {
|
|
|
|
log.Error("Problem with watchdog", err)
|
|
|
|
} else if t != 0 {
|
|
|
|
// Send a ping each half time given
|
|
|
|
t = t / 2
|
|
|
|
log.Info("Watchdog activated with timer each ", t)
|
|
|
|
safe.Go(func() {
|
|
|
|
tick := time.Tick(t)
|
|
|
|
for range tick {
|
2018-03-01 07:10:04 +00:00
|
|
|
_, errHealthCheck := healthcheck.Do(*globalConfiguration)
|
2017-11-23 15:10:04 +00:00
|
|
|
if globalConfiguration.Ping == nil || errHealthCheck == nil {
|
|
|
|
if ok, _ := daemon.SdNotify(false, "WATCHDOG=1"); !ok {
|
|
|
|
log.Error("Fail to tick watchdog")
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
log.Error(errHealthCheck)
|
2017-10-11 08:38:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2017-11-23 15:10:04 +00:00
|
|
|
|
2017-10-11 08:38:03 +00:00
|
|
|
svr.Wait()
|
|
|
|
log.Info("Shutting down")
|
|
|
|
logrus.Exit(0)
|
|
|
|
}
|
|
|
|
|
|
|
|
func configureLogging(globalConfiguration *configuration.GlobalConfiguration) {
|
|
|
|
// configure default log flags
|
|
|
|
fmtlog.SetFlags(fmtlog.Lshortfile | fmtlog.LstdFlags)
|
|
|
|
|
|
|
|
// configure log level
|
2018-03-21 13:42:07 +00:00
|
|
|
// an explicitly defined log level always has precedence. if none is
|
|
|
|
// given and debug mode is disabled, the default is ERROR, and DEBUG
|
|
|
|
// otherwise.
|
|
|
|
levelStr := strings.ToLower(globalConfiguration.LogLevel)
|
|
|
|
if levelStr == "" {
|
|
|
|
levelStr = "error"
|
|
|
|
if globalConfiguration.Debug {
|
|
|
|
levelStr = "debug"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
level, err := logrus.ParseLevel(levelStr)
|
2016-06-02 09:37:51 +00:00
|
|
|
if err != nil {
|
2016-08-19 08:36:54 +00:00
|
|
|
log.Error("Error getting level", err)
|
2016-06-02 09:37:51 +00:00
|
|
|
}
|
|
|
|
log.SetLevel(level)
|
2017-09-21 08:42:02 +00:00
|
|
|
|
2017-10-11 08:38:03 +00:00
|
|
|
// configure log output file
|
2017-09-21 08:42:02 +00:00
|
|
|
logFile := globalConfiguration.TraefikLogsFile
|
|
|
|
if len(logFile) > 0 {
|
2017-10-16 21:10:44 +00:00
|
|
|
log.Warn("top-level traefikLogsFile has been deprecated -- please use traefiklog.filepath")
|
2017-09-21 08:42:02 +00:00
|
|
|
}
|
|
|
|
if globalConfiguration.TraefikLog != nil && len(globalConfiguration.TraefikLog.FilePath) > 0 {
|
|
|
|
logFile = globalConfiguration.TraefikLog.FilePath
|
|
|
|
}
|
|
|
|
|
2017-10-11 08:38:03 +00:00
|
|
|
// configure log format
|
2017-09-21 08:42:02 +00:00
|
|
|
var formatter logrus.Formatter
|
|
|
|
if globalConfiguration.TraefikLog != nil && globalConfiguration.TraefikLog.Format == "json" {
|
|
|
|
formatter = &logrus.JSONFormatter{}
|
|
|
|
} else {
|
2018-02-19 00:04:45 +00:00
|
|
|
disableColors := len(logFile) > 0
|
2017-09-21 08:42:02 +00:00
|
|
|
formatter = &logrus.TextFormatter{DisableColors: disableColors, FullTimestamp: true, DisableSorting: true}
|
|
|
|
}
|
|
|
|
log.SetFormatter(formatter)
|
|
|
|
|
|
|
|
if len(logFile) > 0 {
|
|
|
|
dir := filepath.Dir(logFile)
|
2017-04-27 15:36:04 +00:00
|
|
|
|
2018-02-19 00:04:45 +00:00
|
|
|
if err := os.MkdirAll(dir, 0755); err != nil {
|
2017-04-27 15:36:04 +00:00
|
|
|
log.Errorf("Failed to create log path %s: %s", dir, err)
|
|
|
|
}
|
|
|
|
|
2017-09-21 08:42:02 +00:00
|
|
|
err = log.OpenFile(logFile)
|
2017-10-11 08:38:03 +00:00
|
|
|
logrus.RegisterExitHandler(func() {
|
2017-08-11 10:04:58 +00:00
|
|
|
if err := log.CloseFile(); err != nil {
|
|
|
|
log.Error("Error closing log", err)
|
2016-05-03 14:52:14 +00:00
|
|
|
}
|
2017-10-11 08:38:03 +00:00
|
|
|
})
|
2016-05-03 14:52:14 +00:00
|
|
|
if err != nil {
|
2016-08-19 08:36:54 +00:00
|
|
|
log.Error("Error opening file", err)
|
2016-05-03 14:52:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-07-13 15:18:55 +00:00
|
|
|
|
2017-10-02 08:32:02 +00:00
|
|
|
func checkNewVersion() {
|
2017-11-25 12:36:03 +00:00
|
|
|
ticker := time.Tick(24 * time.Hour)
|
|
|
|
safe.Go(func() {
|
|
|
|
for time.Sleep(10 * time.Minute); ; <-ticker {
|
|
|
|
version.CheckNewVersion()
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func stats(globalConfiguration *configuration.GlobalConfiguration) {
|
|
|
|
if globalConfiguration.SendAnonymousUsage {
|
|
|
|
log.Info(`
|
|
|
|
Stats collection is enabled.
|
|
|
|
Many thanks for contributing to Traefik's improvement by allowing us to receive anonymous information from your configuration.
|
|
|
|
Help us improve Traefik by leaving this feature on :)
|
2018-01-17 11:20:04 +00:00
|
|
|
More details on: https://docs.traefik.io/basics/#collected-data
|
2017-11-25 12:36:03 +00:00
|
|
|
`)
|
|
|
|
collect(globalConfiguration)
|
|
|
|
} else {
|
|
|
|
log.Info(`
|
|
|
|
Stats collection is disabled.
|
|
|
|
Help us improve Traefik by turning this feature on :)
|
2018-01-17 11:20:04 +00:00
|
|
|
More details on: https://docs.traefik.io/basics/#collected-data
|
2017-11-25 12:36:03 +00:00
|
|
|
`)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func collect(globalConfiguration *configuration.GlobalConfiguration) {
|
|
|
|
ticker := time.Tick(24 * time.Hour)
|
2017-10-02 08:32:02 +00:00
|
|
|
safe.Go(func() {
|
2017-11-25 12:36:03 +00:00
|
|
|
for time.Sleep(10 * time.Minute); ; <-ticker {
|
|
|
|
if err := collector.Collect(globalConfiguration); err != nil {
|
|
|
|
log.Debug(err)
|
2017-10-02 08:32:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|