diff --git a/btcd.go b/btcd.go index 3df423cd..064721b6 100644 --- a/btcd.go +++ b/btcd.go @@ -30,16 +30,14 @@ var winServiceMain func() (bool, error) // notified with the server once it is setup so it can gracefully stop it when // requested from the service control manager. func btcdMain(serverChan chan<- *server) error { - // Initialize logging at the default logging level. - setLogLevels(defaultLogLevel) - defer backendLog.Flush() - - // Load configuration and parse command line. + // Load configuration and parse command line. This function also + // initializes logging and configures it accordingly. tcfg, _, err := loadConfig() if err != nil { return err } cfg = tcfg + defer backendLog.Flush() // Show version at startup. btcdLog.Infof("Version %s", version()) diff --git a/config.go b/config.go index a1b11b69..a54c83fc 100644 --- a/config.go +++ b/config.go @@ -28,6 +28,8 @@ const ( defaultConfigFilename = "btcd.conf" defaultDataDirname = "data" defaultLogLevel = "info" + defaultLogDirname = "logs" + defaultLogFilename = "btcd.log" defaultBtcnet = btcwire.MainNet defaultMaxPeers = 125 defaultBanDuration = time.Hour * 24 @@ -43,7 +45,7 @@ var ( knownDbTypes = btcdb.SupportedDBs() defaultRPCKeyFile = filepath.Join(btcdHomeDir, "rpc.key") defaultRPCCertFile = filepath.Join(btcdHomeDir, "rpc.cert") - defaultLogFile = filepath.Join(btcdHomeDir, "logs", "btcd.log") + defaultLogDir = filepath.Join(btcdHomeDir, defaultLogDirname) ) // runServiceCommand is only set to a real function on Windows. It is used @@ -57,6 +59,7 @@ type config struct { ShowVersion bool `short:"V" long:"version" description:"Display version information and exit"` ConfigFile string `short:"C" long:"configfile" description:"Path to configuration file"` DataDir string `short:"b" long:"datadir" description:"Directory to store data"` + LogDir string `long:"logdir" description:"Directory to log output."` AddPeers []string `short:"a" long:"addpeer" description:"Add a peer to connect with at startup"` ConnectPeers []string `long:"connect" description:"Connect only to the specified peers at startup"` DisableListen bool `long:"nolisten" description:"Disable listening for incoming connections -- NOTE: Listening is automatically disabled if the --connect or --proxy options are used without also specifying listen interfaces via --listen"` @@ -280,6 +283,7 @@ func loadConfig() (*config, []string, error) { BanDuration: defaultBanDuration, ConfigFile: defaultConfigFile, DataDir: defaultDataDir, + LogDir: defaultLogDir, DbType: defaultDbType, RPCKey: defaultRPCKeyFile, RPCCert: defaultRPCCertFile, @@ -368,12 +372,30 @@ func loadConfig() (*config, []string, error) { activeNetParams = netParams(btcwire.TestNet) } + // Append the network type to the data directory so it is "namespaced" + // per network. In addition to the block database, there are other + // pieces of data that are saved to disk such as address manager state. + // All data is specific to a network, so namespacing the data directory + // means each individual piece of serialized data does not have to + // worry about changing names per network and such. + cfg.DataDir = cleanAndExpandPath(cfg.DataDir) + cfg.DataDir = filepath.Join(cfg.DataDir, activeNetParams.netName) + + // Append the network type to the log directory so it is "namespaced" + // per network in the same fashion as the data directory. + cfg.LogDir = cleanAndExpandPath(cfg.LogDir) + cfg.LogDir = filepath.Join(cfg.LogDir, activeNetParams.netName) + // Special show command to list supported subsystems and exit. if cfg.DebugLevel == "show" { fmt.Println("Supported subsystems", supportedSubsystems()) os.Exit(0) } + // Initialize logging at the default logging level. + initSeelogLogger(filepath.Join(cfg.LogDir, defaultLogFilename)) + setLogLevels(defaultLogLevel) + // Parse, validate, and set debug log level(s). if err := parseAndSetDebugLevels(cfg.DebugLevel); err != nil { err := fmt.Errorf("%s: %v", "loadConfig", err.Error()) @@ -404,15 +426,6 @@ func loadConfig() (*config, []string, error) { } } - // Append the network type to the data directory so it is "namespaced" - // per network. In addition to the block database, there are other - // pieces of data that are saved to disk such as address manager state. - // All data is specific to a network, so namespacing the data directory - // means each individual piece of serialized data does not have to - // worry about changing names per network and such. - cfg.DataDir = cleanAndExpandPath(cfg.DataDir) - cfg.DataDir = filepath.Join(cfg.DataDir, activeNetParams.netName) - // Don't allow ban durations that are too short. if cfg.BanDuration < time.Duration(time.Second) { str := "%s: The banduration option may not be less than 1s -- parsed [%v]" diff --git a/log.go b/log.go index 35b51374..0229da4b 100644 --- a/log.go +++ b/log.go @@ -122,10 +122,9 @@ func useLogger(subsystemID string, logger btclog.Logger) { } } -// newSeelogLogger creates a new seelog logger. -func newSeelogLogger() seelog.LoggerInterface { - // - +// initSeelogLogger initializes a new seelog logger that is used as the backend +// for all logging subsytems. +func initSeelogLogger(logFile string) { config := ` @@ -137,7 +136,7 @@ func newSeelogLogger() seelog.LoggerInterface { ` - config = fmt.Sprintf(config, defaultLogFile) + config = fmt.Sprintf(config, logFile) logger, err := seelog.LoggerFromConfigAsString(config) if err != nil { @@ -145,18 +144,13 @@ func newSeelogLogger() seelog.LoggerInterface { os.Exit(1) } - return logger + backendLog = logger } // setLogLevel sets the logging level for provided subsystem. Invalid // subsystems are ignored. Uninitialized subsystems are dynamically created as // needed. func setLogLevel(subsystemID string, logLevel string) { - // Create the backend seelog logger if needed. - if backendLog == seelog.Disabled { - backendLog = newSeelogLogger() - } - // Ignore invalid subsystems. logger, ok := subsystemLoggers[subsystemID] if !ok {