2015-04-02 00:34:32 +08:00
package main
import (
2018-11-06 05:34:28 +08:00
"context"
"errors"
2015-04-02 00:34:32 +08:00
"flag"
2015-04-08 00:24:34 +08:00
"fmt"
2015-04-02 00:34:32 +08:00
"log"
2017-03-30 09:28:43 +08:00
"net/http"
_ "net/http/pprof" // Comment this line to disable pprof endpoint.
2015-04-02 00:34:32 +08:00
"os"
"os/signal"
2019-12-18 04:44:17 +08:00
"sort"
2015-04-02 00:34:32 +08:00
"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"
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"
2019-09-21 07:50:19 +08:00
"github.com/influxdata/telegraf/internal/goplugin"
2016-10-01 05:37:56 +08:00
"github.com/influxdata/telegraf/logger"
2016-10-04 01:49:30 +08:00
_ "github.com/influxdata/telegraf/plugins/aggregators/all"
2016-03-04 00:09:49 +08:00
"github.com/influxdata/telegraf/plugins/inputs"
2016-01-21 02:57:35 +08:00
_ "github.com/influxdata/telegraf/plugins/inputs/all"
2016-03-06 20:08:51 +08:00
"github.com/influxdata/telegraf/plugins/outputs"
2016-01-21 02:57:35 +08:00
_ "github.com/influxdata/telegraf/plugins/outputs/all"
2022-01-13 06:54:42 +08:00
_ "github.com/influxdata/telegraf/plugins/parsers/all"
2016-09-08 22:22:10 +08:00
_ "github.com/influxdata/telegraf/plugins/processors/all"
2021-07-16 00:11:58 +08:00
"gopkg.in/tomb.v1"
2015-04-02 00:34:32 +08:00
)
2021-05-19 05:20:13 +08:00
type sliceFlags [ ] string
func ( i * sliceFlags ) String ( ) string {
s := strings . Join ( * i , " " )
return "[" + s + "]"
}
func ( i * sliceFlags ) Set ( value string ) error {
* i = append ( * i , value )
return nil
}
2020-04-21 01:49:10 +08:00
// If you update these, update usage.go and usage_windows.go
2015-08-25 04:52:46 +08:00
var fDebug = flag . Bool ( "debug" , false ,
2016-10-01 05:37:56 +08:00
"turn on debug logging" )
2017-03-30 09:28:43 +08:00
var pprofAddr = flag . String ( "pprof-addr" , "" ,
"pprof address to listen on, not activate pprof if empty" )
2016-01-16 03:25:56 +08:00
var fQuiet = flag . Bool ( "quiet" , false ,
"run in quiet mode" )
2020-04-21 01:49:10 +08:00
var fTest = flag . Bool ( "test" , false , "enable test mode: gather metrics, print them out, and exit. Note: Test mode only runs inputs, not processors, aggregators, or outputs" )
2019-06-15 03:06:25 +08:00
var fTestWait = flag . Int ( "test-wait" , 0 , "wait up to this many seconds for service inputs to complete in test mode" )
2021-05-19 05:20:13 +08:00
var fConfigs sliceFlags
var fConfigDirs sliceFlags
2021-07-16 00:11:58 +08:00
var fWatchConfig = flag . String ( "watch-config" , "" , "Monitoring config changes [notify, poll]" )
2018-09-11 02:53:04 +08:00
var fVersion = flag . Bool ( "version" , false , "display the version and exit" )
2015-08-25 04:52:46 +08:00
var fSampleConfig = flag . Bool ( "sample-config" , false ,
"print out full sample configuration" )
2015-06-19 02:31:16 +08:00
var fPidfile = flag . String ( "pidfile" , "" , "file to write our pid to" )
2021-12-02 03:38:43 +08:00
var fDeprecationList = flag . Bool ( "deprecation-list" , false ,
"print all deprecated plugins or plugin options." )
2019-04-26 11:34:40 +08:00
var fSectionFilters = flag . String ( "section-filter" , "" ,
"filter the sections to print, separator is ':'. Valid values are 'agent', 'global_tags', 'outputs', 'processors', 'aggregators' and 'inputs'" )
2016-01-08 04:39:43 +08:00
var fInputFilters = flag . String ( "input-filter" , "" ,
2016-01-18 06:32:24 +08:00
"filter the inputs to enable, separator is :" )
2016-03-07 18:42:01 +08:00
var fInputList = flag . Bool ( "input-list" , false ,
2016-03-18 10:06:44 +08:00
"print available input plugins." )
2016-01-08 04:39:43 +08:00
var fOutputFilters = flag . String ( "output-filter" , "" ,
2015-09-22 09:38:57 +08:00
"filter the outputs to enable, separator is :" )
2016-03-06 20:08:51 +08:00
var fOutputList = flag . Bool ( "output-list" , false ,
2016-03-07 18:42:01 +08:00
"print available output plugins." )
2016-10-05 17:58:30 +08:00
var fAggregatorFilters = flag . String ( "aggregator-filter" , "" ,
"filter the aggregators to enable, separator is :" )
var fProcessorFilters = flag . String ( "processor-filter" , "" ,
"filter the processors to enable, separator is :" )
2015-08-25 04:52:46 +08:00
var fUsage = flag . String ( "usage" , "" ,
2017-08-12 07:26:00 +08:00
"print usage for a plugin, ie, 'telegraf --usage mysql'" )
2021-03-23 01:21:36 +08:00
//nolint:varcheck,unused // False positive - this var is used for non-default build tag: windows
2016-08-08 22:55:16 +08:00
var fService = flag . String ( "service" , "" ,
2018-09-11 02:53:04 +08:00
"operate on the service (windows only)" )
2021-03-23 01:21:36 +08:00
//nolint:varcheck,unused // False positive - this var is used for non-default build tag: windows
var fServiceName = flag . String ( "service-name" , "telegraf" ,
"service name (windows only)" )
//nolint:varcheck,unused // False positive - this var is used for non-default build tag: windows
var fServiceDisplayName = flag . String ( "service-display-name" , "Telegraf Data Collector Service" ,
"service display name (windows only)" )
2022-02-04 00:23:52 +08:00
//nolint:varcheck,unused // False positive - this var is used for non-default build tag: windows
var fServiceAutoRestart = flag . Bool ( "service-auto-restart" , false ,
"auto restart service on failure (windows only)" )
//nolint:varcheck,unused // False positive - this var is used for non-default build tag: windows
var fServiceRestartDelay = flag . String ( "service-restart-delay" , "5m" ,
"delay before service auto restart, default is 5m (windows only)" )
2021-03-23 01:21:36 +08:00
//nolint:varcheck,unused // False positive - this var is used for non-default build tag: windows
var fRunAsConsole = flag . Bool ( "console" , false ,
"run as console application (windows only)" )
2019-07-30 12:34:03 +08:00
var fPlugins = flag . String ( "plugin-directory" , "" ,
"path to directory containing external plugins" )
2020-06-02 06:26:20 +08:00
var fRunOnce = flag . Bool ( "once" , false , "run one gather and exit" )
2016-01-08 06:21:10 +08:00
2016-05-03 07:22:28 +08:00
var (
2018-08-13 07:52:35 +08:00
version string
commit string
branch string
2016-05-03 07:22:28 +08:00
)
2015-04-02 00:34:32 +08:00
2016-07-16 05:00:16 +08:00
var stop chan struct { }
2017-02-02 01:14:47 +08:00
func reloadLoop (
inputFilters [ ] string ,
outputFilters [ ] string ,
) {
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 )
2021-07-16 00:11:58 +08:00
if * fWatchConfig != "" {
for _ , fConfig := range fConfigs {
if _ , err := os . Stat ( fConfig ) ; err == nil {
go watchLocalConfig ( signals , fConfig )
} 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 ( )
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
2018-11-06 05:34:28 +08:00
err := runAgent ( ctx , inputFilters , outputFilters )
2019-06-01 07:50:44 +08:00
if err != nil && err != context . Canceled {
2018-11-06 05:34:28 +08:00
log . Fatalf ( "E! [telegraf] Error running agent: %v" , err )
}
}
}
2021-07-16 00:11:58 +08:00
func watchLocalConfig ( signals chan os . Signal , fConfig string ) {
var mytomb tomb . Tomb
var watcher watch . FileWatcher
if * fWatchConfig == "poll" {
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
}
2018-11-06 05:34:28 +08:00
func runAgent ( ctx context . Context ,
inputFilters [ ] string ,
outputFilters [ ] string ,
) error {
// If no other options are specified, load the config file and run.
c := config . NewConfig ( )
c . OutputFilters = outputFilters
c . InputFilters = inputFilters
2021-05-19 05:20:13 +08:00
var err error
// providing no "config" flag should load default config
if len ( fConfigs ) == 0 {
err = c . LoadConfig ( "" )
if err != nil {
return err
}
}
for _ , fConfig := range fConfigs {
err = c . LoadConfig ( fConfig )
if err != nil {
return err
}
2018-11-06 05:34:28 +08:00
}
2021-05-19 05:20:13 +08:00
for _ , fConfigDirectory := range fConfigDirs {
err = c . LoadDirectory ( fConfigDirectory )
2018-11-06 05:34:28 +08:00
if err != nil {
return err
2016-01-17 16:08:02 +08:00
}
2018-11-06 05:34:28 +08:00
}
2021-05-19 05:20:13 +08:00
2018-11-06 05:34:28 +08:00
if ! * fTest && len ( c . Outputs ) == 0 {
return errors . New ( "Error: no outputs found, did you provide a valid config file?" )
}
2019-07-30 12:34:03 +08:00
if * fPlugins == "" && len ( c . Inputs ) == 0 {
2018-11-06 05:34:28 +08:00
return errors . New ( "Error: no inputs found, did you provide a valid config file?" )
}
2021-04-10 01:15:04 +08:00
if int64 ( c . Agent . Interval ) <= 0 {
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 {
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-02-01 04:30:52 +08:00
telegraf . Debug = c . Agent . Debug || * fDebug
2019-05-04 01:25:28 +08:00
logConfig := logger . LogConfig {
2021-03-19 05:21:30 +08:00
Debug : telegraf . Debug ,
2022-02-01 04:30:52 +08:00
Quiet : c . Agent . Quiet || * fQuiet ,
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
}
logger . SetupLogging ( logConfig )
2018-11-06 05:34:28 +08:00
2022-02-01 04:30:52 +08:00
log . Printf ( "I! Starting Telegraf %s" , version )
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 ( ) , " " ) )
2021-12-08 06:56:18 +08:00
if ! * fRunOnce && ( * fTest || * fTestWait != 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-02-01 04:30:52 +08:00
ag , err := agent . NewAgent ( c )
if err != nil {
return err
}
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 )
2021-12-08 06:56:18 +08:00
if * fRunOnce {
wait := time . Duration ( * fTestWait ) * time . Second
return ag . Once ( ctx , wait )
}
if * fTest || * fTestWait != 0 {
wait := time . Duration ( * fTestWait ) * time . Second
return ag . Test ( ctx , wait )
}
2018-11-06 05:34:28 +08:00
if * fPidfile != "" {
f , err := os . OpenFile ( * fPidfile , os . O_CREATE | os . O_WRONLY , 0644 )
if err != nil {
log . Printf ( "E! Unable to create pidfile: %s" , err )
} else {
fmt . Fprintf ( f , "%d\n" , os . Getpid ( ) )
f . Close ( )
defer func ( ) {
err := os . Remove ( * fPidfile )
if err != nil {
log . Printf ( "E! Unable to remove pidfile: %s" , err )
}
} ( )
}
}
return ag . Run ( ctx )
2015-04-02 00:34:32 +08:00
}
2016-01-08 04:39:43 +08:00
2016-02-02 08:44:19 +08:00
func usageExit ( rc int ) {
2018-05-05 05:16:21 +08:00
fmt . Println ( internal . Usage )
2016-02-02 08:44:19 +08:00
os . Exit ( rc )
2016-01-08 04:39:43 +08:00
}
2016-07-16 05:00:16 +08:00
2018-08-13 07:52:35 +08:00
func formatFullVersion ( ) string {
var parts = [ ] string { "Telegraf" }
if version != "" {
parts = append ( parts , version )
} else {
parts = append ( parts , "unknown" )
2017-06-28 04:24:06 +08:00
}
2018-08-13 07:52:35 +08:00
if branch != "" || commit != "" {
if branch == "" {
branch = "unknown"
}
if commit == "" {
commit = "unknown"
}
git := fmt . Sprintf ( "(git: %s %s)" , branch , commit )
parts = append ( parts , git )
}
return strings . Join ( parts , " " )
2017-06-28 04:24:06 +08:00
}
2016-07-16 05:00:16 +08:00
func main ( ) {
2021-05-19 05:20:13 +08:00
flag . Var ( & fConfigs , "config" , "configuration file to load" )
flag . Var ( & fConfigDirs , "config-directory" , "directory containing additional *.conf files" )
2016-10-05 20:53:43 +08:00
flag . Usage = func ( ) { usageExit ( 0 ) }
2016-10-01 05:37:56 +08:00
flag . Parse ( )
2017-02-02 01:14:47 +08:00
args := flag . Args ( )
2019-04-26 11:34:40 +08:00
sectionFilters , inputFilters , outputFilters := [ ] string { } , [ ] string { } , [ ] string { }
if * fSectionFilters != "" {
sectionFilters = strings . Split ( ":" + strings . TrimSpace ( * fSectionFilters ) + ":" , ":" )
}
2017-02-02 01:14:47 +08:00
if * fInputFilters != "" {
inputFilters = strings . Split ( ":" + strings . TrimSpace ( * fInputFilters ) + ":" , ":" )
}
if * fOutputFilters != "" {
outputFilters = strings . Split ( ":" + strings . TrimSpace ( * fOutputFilters ) + ":" , ":" )
}
aggregatorFilters , processorFilters := [ ] string { } , [ ] string { }
if * fAggregatorFilters != "" {
aggregatorFilters = strings . Split ( ":" + strings . TrimSpace ( * fAggregatorFilters ) + ":" , ":" )
}
if * fProcessorFilters != "" {
processorFilters = strings . Split ( ":" + strings . TrimSpace ( * fProcessorFilters ) + ":" , ":" )
}
2019-07-30 12:47:49 +08:00
logger . SetupLogging ( logger . LogConfig { } )
2021-12-02 03:38:43 +08:00
// Configure version
if err := internal . SetVersion ( version ) ; err != nil {
log . Println ( "Telegraf version already configured to: " + internal . Version ( ) )
}
2019-07-30 12:34:03 +08:00
// Load external plugins, if requested.
if * fPlugins != "" {
2019-07-30 12:47:49 +08:00
log . Printf ( "I! Loading external plugins from: %s" , * fPlugins )
2019-09-21 07:50:19 +08:00
if err := goplugin . LoadExternalPlugins ( * fPlugins ) ; err != nil {
2019-07-30 12:47:49 +08:00
log . Fatal ( "E! " + err . Error ( ) )
2019-07-30 12:34:03 +08:00
}
}
2017-03-30 09:28:43 +08:00
if * pprofAddr != "" {
go func ( ) {
pprofHostPort := * pprofAddr
parts := strings . Split ( pprofHostPort , ":" )
if len ( parts ) == 2 && parts [ 0 ] == "" {
pprofHostPort = fmt . Sprintf ( "localhost:%s" , parts [ 1 ] )
}
pprofHostPort = "http://" + pprofHostPort + "/debug/pprof"
log . Printf ( "I! Starting pprof HTTP server at: %s" , pprofHostPort )
if err := http . ListenAndServe ( * pprofAddr , nil ) ; err != nil {
log . Fatal ( "E! " + err . Error ( ) )
}
} ( )
}
2017-02-02 01:14:47 +08:00
if len ( args ) > 0 {
switch args [ 0 ] {
case "version" :
2018-08-13 07:52:35 +08:00
fmt . Println ( formatFullVersion ( ) )
2017-02-02 01:14:47 +08:00
return
case "config" :
config . PrintSampleConfig (
2019-04-26 11:34:40 +08:00
sectionFilters ,
2017-02-02 01:14:47 +08:00
inputFilters ,
outputFilters ,
aggregatorFilters ,
processorFilters ,
)
return
}
}
// switch for flags which just do something and exit immediately
switch {
2021-12-02 03:38:43 +08:00
case * fDeprecationList :
c := config . NewConfig ( )
infos := c . CollectDeprecationInfos (
inputFilters ,
outputFilters ,
aggregatorFilters ,
processorFilters ,
)
//nolint:revive // We will notice if Println fails
fmt . Println ( "Deprecated Input Plugins: " )
c . PrintDeprecationList ( infos [ "inputs" ] )
//nolint:revive // We will notice if Println fails
fmt . Println ( "Deprecated Output Plugins: " )
c . PrintDeprecationList ( infos [ "outputs" ] )
//nolint:revive // We will notice if Println fails
fmt . Println ( "Deprecated Processor Plugins: " )
c . PrintDeprecationList ( infos [ "processors" ] )
//nolint:revive // We will notice if Println fails
fmt . Println ( "Deprecated Aggregator Plugins: " )
c . PrintDeprecationList ( infos [ "aggregators" ] )
return
2017-02-02 01:14:47 +08:00
case * fOutputList :
2019-12-18 04:44:17 +08:00
fmt . Println ( "Available Output Plugins: " )
names := make ( [ ] string , 0 , len ( outputs . Outputs ) )
2018-10-20 04:32:54 +08:00
for k := range outputs . Outputs {
2019-12-18 04:44:17 +08:00
names = append ( names , k )
}
sort . Strings ( names )
for _ , k := range names {
2017-02-02 01:14:47 +08:00
fmt . Printf ( " %s\n" , k )
}
return
case * fInputList :
fmt . Println ( "Available Input Plugins:" )
2019-12-18 04:44:17 +08:00
names := make ( [ ] string , 0 , len ( inputs . Inputs ) )
2018-10-20 04:32:54 +08:00
for k := range inputs . Inputs {
2019-12-18 04:44:17 +08:00
names = append ( names , k )
}
sort . Strings ( names )
for _ , k := range names {
2017-02-02 01:14:47 +08:00
fmt . Printf ( " %s\n" , k )
}
return
case * fVersion :
2018-08-13 07:52:35 +08:00
fmt . Println ( formatFullVersion ( ) )
2017-02-02 01:14:47 +08:00
return
case * fSampleConfig :
config . PrintSampleConfig (
2019-04-26 11:34:40 +08:00
sectionFilters ,
2017-02-02 01:14:47 +08:00
inputFilters ,
outputFilters ,
aggregatorFilters ,
processorFilters ,
)
return
case * fUsage != "" :
err := config . PrintInputConfig ( * fUsage )
err2 := config . PrintOutputConfig ( * fUsage )
if err != nil && err2 != nil {
log . Fatalf ( "E! %s and %s" , err , err2 )
}
return
}
2020-04-21 01:49:10 +08:00
run (
inputFilters ,
outputFilters ,
)
2019-03-27 09:17:27 +08:00
}