Add --logdir option to specify logging directory.

This commit adds a new option, --logdir, which works in the same fashion
as the --datadir option.  Consequently, the logging directory is name
"namespaced" by the network as well.  This resolves the issue where two
btcd instances running (one for mainnet and one for testnet) would
overwrite each other's log files by default.

It also provides the user with a method to change the logging location to
non-default locations if they prefer.  For example, it enables multiple
btcd instances on the same network to specify unique logging directories
(even though running multiple btcd instances on the same network is not
the most sane configuration).

Closes #95.
This commit is contained in:
Dave Collins 2014-02-12 15:43:27 -06:00
parent e20a3e9f2c
commit f9922c7305
3 changed files with 31 additions and 26 deletions

View file

@ -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())

View file

@ -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]"

16
log.go
View file

@ -122,10 +122,9 @@ func useLogger(subsystemID string, logger btclog.Logger) {
}
}
// newSeelogLogger creates a new seelog logger.
func newSeelogLogger() seelog.LoggerInterface {
// <seelog type="sync" minlevel="trace">
// initSeelogLogger initializes a new seelog logger that is used as the backend
// for all logging subsytems.
func initSeelogLogger(logFile string) {
config := `
<seelog type="adaptive" mininterval="2000000" maxinterval="100000000"
critmsgcount="500" minlevel="trace">
@ -137,7 +136,7 @@ func newSeelogLogger() seelog.LoggerInterface {
<format id="all" format="%%Time %%Date [%%LEV] %%Msg%%n" />
</formats>
</seelog>`
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 {