@@ -37,20 +37,23 @@ import (
3737
3838 "github.com/dchest/uniuri"
3939 homedir "github.com/mitchellh/go-homedir"
40- logging "github.com/op/go-logging"
4140 "github.com/pkg/errors"
41+ "github.com/rs/zerolog"
4242 "github.com/spf13/cobra"
4343 "github.com/spf13/pflag"
4444
4545 _ "github.com/arangodb-helper/arangodb/client"
46+ "github.com/arangodb-helper/arangodb/pkg/logging"
4647 "github.com/arangodb-helper/arangodb/pkg/net"
48+ "github.com/arangodb-helper/arangodb/pkg/terminal"
4749 service "github.com/arangodb-helper/arangodb/service"
4850)
4951
5052// Configuration data with defaults:
5153
5254const (
5355 projectName = "arangodb"
56+ logFileName = projectName + ".log"
5457 defaultDockerGCDelay = time .Minute * 10
5558 defaultDockerStarterImage = "arangodb/arangodb-starter"
5659 defaultArangodPath = "/usr/sbin/arangod"
@@ -78,25 +81,31 @@ var (
7881 Short : "Show ArangoDB version" ,
7982 Run : cmdShowVersionRun ,
8083 }
81- log = logging .MustGetLogger (projectName )
82- showVersion bool
83- id string
84- agencySize int
85- arangodPath string
86- arangodJSPath string
87- arangoSyncPath string
88- masterPort int
89- rrPath string
90- startAgent []bool
91- startDBserver []bool
92- startCoordinator []bool
93- startActiveFailover []bool
94- startSyncMaster []bool
95- startSyncWorker []bool
96- startLocalSlaves bool
97- mode string
98- dataDir string
99- logDir string // Custom log directory (default "")
84+ log zerolog.Logger
85+ logService logging.Service
86+ showVersion bool
87+ id string
88+ agencySize int
89+ arangodPath string
90+ arangodJSPath string
91+ arangoSyncPath string
92+ masterPort int
93+ rrPath string
94+ startAgent []bool
95+ startDBserver []bool
96+ startCoordinator []bool
97+ startActiveFailover []bool
98+ startSyncMaster []bool
99+ startSyncWorker []bool
100+ startLocalSlaves bool
101+ mode string
102+ dataDir string
103+ logDir string // Custom log directory (default "")
104+ logOutput struct {
105+ Color bool
106+ Console bool
107+ File bool
108+ }
100109 ownAddress string
101110 bindAddress string
102111 masterAddresses []string
@@ -139,6 +148,16 @@ var (
139148)
140149
141150func init () {
151+ log , _ = logging .NewRootLogger (logging.LoggerOutputOptions {
152+ Stderr : true ,
153+ })
154+
155+ defaultLogColor := true
156+ if ! terminal .IsTerminal () {
157+ // We're not running on a terminal, avoid colorizing logs
158+ defaultLogColor = false
159+ }
160+
142161 cmdMain .AddCommand (cmdVersion )
143162
144163 pf := cmdMain .PersistentFlags ()
@@ -160,6 +179,9 @@ func init() {
160179 f .BoolVar (& enableSync , "starter.sync" , false , "If set, the starter will also start arangosync instances" )
161180
162181 pf .BoolVar (& verbose , "log.verbose" , false , "Turn on debug logging" )
182+ pf .BoolVar (& logOutput .Console , "log.console" , true , "Send log output to console" )
183+ pf .BoolVar (& logOutput .File , "log.file" , true , "Send log output to file" )
184+ pf .BoolVar (& logOutput .Color , "log.color" , defaultLogColor , "Colorize the log output" )
163185 pf .StringVar (& logDir , "log.dir" , getEnvVar ("LOG_DIR" , "" ), "Custom log file directory." )
164186 f .IntVar (& logRotateFilesToKeep , "log.rotate-files-to-keep" , defaultLogRotateFilesToKeep , "Number of files to keep when rotating log files" )
165187 f .DurationVar (& logRotateInterval , "log.rotate-interval" , defaultLogRotateInterval , "Time between log rotations (0 disables log rotation)" )
@@ -244,7 +266,7 @@ func init() {
244266 option := getPassthroughOption (a , fullArgPrefix , ptPrefix .Prefix , f )
245267 if option != nil {
246268 if option .IsForbidden () {
247- log .Fatalf ("Option '%s' is essential to the starters behavior and cannot be overwritten." , option .FormattedOptionName ())
269+ log .Fatal (). Msgf ("Option '%s' is essential to the starters behavior and cannot be overwritten." , option .FormattedOptionName ())
248270 }
249271 fullOptionName := ptPrefix .Prefix + "." + option .Name
250272 f .StringSliceVar (ptPrefix .FieldSelector (option ), fullOptionName , nil , fmt .Sprintf ("Passed through to %s as --%s" , ptPrefix .Usage , option .Name ))
@@ -360,11 +382,11 @@ func findExecutable(processName, defaultPath string) (executablePath string, isB
360382 }
361383 }
362384 } else {
363- log .Errorf ("Could not read directory %s to look for executable." , basePath )
385+ log .Error (). Msgf ("Could not read directory %s to look for executable." , basePath )
364386 }
365387 d .Close ()
366388 } else {
367- log .Errorf ("Could not open directory %s to look for executable." , basePath )
389+ log .Error (). Msgf ("Could not open directory %s to look for executable." , basePath )
368390 }
369391 sort .Sort (sort .Reverse (sort .StringSlice (foundPaths )))
370392 pathList = append (pathList , foundPaths ... )
@@ -420,7 +442,7 @@ func main() {
420442
421443// Cobra run function using the usage of the given command
422444func cmdShowUsage (cmd * cobra.Command , args []string ) {
423- log .Infof ("%s version %s, build %s" , projectName , projectVersion , projectBuild )
445+ log .Info (). Msgf ("%s version %s, build %s" , projectName , projectVersion , projectBuild )
424446 cmd .Usage ()
425447}
426448
@@ -432,15 +454,15 @@ func cmdShowVersionRun(cmd *cobra.Command, args []string) {
432454}
433455
434456func cmdMainRun (cmd * cobra.Command , args []string ) {
435- log .Infof ("Starting %s version %s, build %s" , projectName , projectVersion , projectBuild )
457+ // Setup log level
458+ configureLogging ()
459+
460+ log .Info ().Msgf ("Starting %s version %s, build %s" , projectName , projectVersion , projectBuild )
436461
437462 if len (args ) > 0 {
438- log .Fatalf ("Expected no arguments, got %q" , args )
463+ log .Fatal (). Msgf ("Expected no arguments, got %q" , args )
439464 }
440465
441- // Setup log level
442- configureLogging ()
443-
444466 // Create service
445467 svc , bsCfg := mustPrepareService (true )
446468
@@ -453,25 +475,41 @@ func cmdMainRun(cmd *cobra.Command, args []string) {
453475 // Read RECOVERY file if it exists and perform recovery.
454476 bsCfg , err := svc .PerformRecovery (rootCtx , bsCfg )
455477 if err != nil {
456- log .Fatalf ( "Failed to recover: %#v" , err )
478+ log .Fatal (). Err ( err ). Msg ( "Failed to recover" )
457479 }
458480
459481 // Read setup.json (if exists)
460482 bsCfg , peers , relaunch , _ := service .ReadSetupConfig (log , dataDir , bsCfg )
461483
462484 // Run the service
463485 if err := svc .Run (rootCtx , bsCfg , peers , relaunch ); err != nil {
464- log .Fatalf ( "Failed to run service: %#v" , err )
486+ log .Fatal (). Err ( err ). Msg ( "Failed to run service" )
465487 }
466488}
467489
468490// configureLogging configures the log object according to command line arguments.
469491func configureLogging () {
492+ logOpts := logging.LoggerOutputOptions {
493+ Stderr : logOutput .Console ,
494+ Color : logOutput .Color ,
495+ }
496+ if logOutput .File {
497+ if logDir != "" {
498+ logOpts .LogFile = filepath .Join (logDir , logFileName )
499+ } else {
500+ logOpts .LogFile = filepath .Join (dataDir , logFileName )
501+ }
502+ }
503+ defaultLevel := "INFO"
470504 if verbose {
471- logging .SetLevel (logging .DEBUG , projectName )
472- } else {
473- logging .SetLevel (logging .INFO , projectName )
505+ defaultLevel = "DEBUG"
506+ }
507+ var err error
508+ logService , err = logging .NewService (defaultLevel , logOpts )
509+ if err != nil {
510+ log .Fatal ().Err (err ).Msg ("Failed to configure logging service" )
474511 }
512+ log = logService .MustGetLogger (projectName )
475513}
476514
477515// mustPrepareService creates a new Service for the configured arguments,
@@ -515,7 +553,7 @@ func mustPrepareService(generateAutoKeyFile bool) (*service.Service, service.Boo
515553 }
516554 imagePullPolicy , err := service .ParseImagePullPolicy (dockerImagePullPolicy , dockerArangodImage )
517555 if err != nil {
518- log .Fatalf ( "Unsupport image pull policy '%s': %#v " , dockerImagePullPolicy , err )
556+ log .Fatal (). Err ( err ). Msgf ( "Unsupport image pull policy '%s'" , dockerImagePullPolicy )
519557 }
520558
521559 // Expand home-dis (~) in paths
@@ -534,8 +572,8 @@ func mustPrepareService(generateAutoKeyFile bool) (*service.Service, service.Boo
534572 if _ , err := os .Stat (arangodPath ); os .IsNotExist (err ) {
535573 showArangodExecutableNotFoundHelp (arangodPath )
536574 }
537- log .Debugf ("Using %s as default arangod executable." , arangodPath )
538- log .Debugf ("Using %s as default JS dir." , arangodJSPath )
575+ log .Debug (). Msgf ("Using %s as default arangod executable." , arangodPath )
576+ log .Debug (). Msgf ("Using %s as default JS dir." , arangodJSPath )
539577 }
540578
541579 // Sort out work directory:
@@ -544,14 +582,14 @@ func mustPrepareService(generateAutoKeyFile bool) (*service.Service, service.Boo
544582 }
545583 dataDir , _ = filepath .Abs (dataDir )
546584 if err := os .MkdirAll (dataDir , 0755 ); err != nil {
547- log .Fatalf ( "Cannot create data directory %s because %v , giving up." , dataDir , err )
585+ log .Fatal (). Err ( err ). Msgf ( "Cannot create data directory %s, giving up." , dataDir )
548586 }
549587
550588 // Make custom log directory absolute
551589 if logDir != "" {
552590 logDir , _ = filepath .Abs (logDir )
553591 if err := os .MkdirAll (logDir , 0755 ); err != nil {
554- log .Fatalf ( "Cannot create custom log directory %s because %v , giving up." , logDir , err )
592+ log .Fatal (). Err ( err ). Msgf ( "Cannot create custom log directory %s, giving up." , logDir )
555593 }
556594 }
557595
@@ -560,7 +598,7 @@ func mustPrepareService(generateAutoKeyFile bool) (*service.Service, service.Boo
560598 if jwtSecretFile != "" {
561599 content , err := ioutil .ReadFile (jwtSecretFile )
562600 if err != nil {
563- log .Fatalf ( "Failed to read JWT secret file '%s': %v " , jwtSecretFile , err )
601+ log .Fatal (). Err ( err ). Msgf ( "Failed to read JWT secret file '%s'" , jwtSecretFile )
564602 }
565603 jwtSecret = strings .TrimSpace (string (content ))
566604 }
@@ -582,10 +620,10 @@ func mustPrepareService(generateAutoKeyFile bool) (*service.Service, service.Boo
582620 Organization : sslAutoOrganization ,
583621 }, dataDir )
584622 if err != nil {
585- log .Fatalf ( "Failed to create keyfile: %v" , err )
623+ log .Fatal (). Err ( err ). Msg ( "Failed to create keyfile" )
586624 }
587625 sslKeyFile = keyFile
588- log .Infof ("Using self-signed certificate: %s" , sslKeyFile )
626+ log .Info (). Msgf ("Using self-signed certificate: %s" , sslKeyFile )
589627 }
590628
591629 // Check sync settings
@@ -599,7 +637,7 @@ func mustPrepareService(generateAutoKeyFile bool) (*service.Service, service.Boo
599637 if _ , err := os .Stat (arangoSyncPath ); os .IsNotExist (err ) {
600638 showArangoSyncExecutableNotFoundHelp (arangoSyncPath )
601639 }
602- log .Debugf ("Using %s as default arangosync executable." , arangoSyncPath )
640+ log .Debug (). Msgf ("Using %s as default arangosync executable." , arangoSyncPath )
603641 } else {
604642 // Check arangosync docker image
605643 if dockerArangoSyncImage == "" {
@@ -694,7 +732,7 @@ func mustPrepareService(generateAutoKeyFile bool) (*service.Service, service.Boo
694732 for _ , ptOpt := range passthroughOptions {
695733 serviceConfig .PassthroughOptions = append (serviceConfig .PassthroughOptions , * ptOpt )
696734 }
697- service := service .NewService (context .Background (), log , serviceConfig , false )
735+ service := service .NewService (context .Background (), log , logService , serviceConfig , false )
698736
699737 return service , bsCfg
700738}
@@ -713,7 +751,7 @@ func getEnvVar(key, defaultValue string) string {
713751func mustExpand (s string ) string {
714752 result , err := homedir .Expand (s )
715753 if err != nil {
716- log .Fatalf ( "Cannot expand '%s': %#v " , s , err )
754+ log .Fatal (). Err ( err ). Msgf ( "Cannot expand '%s'" , s )
717755 }
718756 return result
719757}
@@ -730,7 +768,7 @@ func mustGetOptionalBoolRef(flagName string, v []bool) *bool {
730768 x := v [0 ]
731769 return & x
732770 default :
733- log .Fatalf ("Expected 0 or 1 %s options, got %d" , flagName , len (v ))
771+ log .Fatal (). Msgf ("Expected 0 or 1 %s options, got %d" , flagName , len (v ))
734772 return nil
735773 }
736774}
0 commit comments