1// Copyright (c) 2013-2017 The btcsuite developers 2// Copyright (c) 2017 The Decred developers 3// Use of this source code is governed by an ISC 4// license that can be found in the LICENSE file. 5 6package main 7 8import ( 9 "fmt" 10 "os" 11 "path/filepath" 12 13 "github.com/btcsuite/btcd/addrmgr" 14 "github.com/btcsuite/btcd/blockchain" 15 "github.com/btcsuite/btcd/blockchain/indexers" 16 "github.com/btcsuite/btcd/connmgr" 17 "github.com/btcsuite/btcd/database" 18 "github.com/btcsuite/btcd/mempool" 19 "github.com/btcsuite/btcd/mining" 20 "github.com/btcsuite/btcd/mining/cpuminer" 21 "github.com/btcsuite/btcd/netsync" 22 "github.com/btcsuite/btcd/peer" 23 "github.com/btcsuite/btcd/txscript" 24 25 "github.com/btcsuite/btclog" 26 "github.com/jrick/logrotate/rotator" 27) 28 29// logWriter implements an io.Writer that outputs to both standard output and 30// the write-end pipe of an initialized log rotator. 31type logWriter struct{} 32 33func (logWriter) Write(p []byte) (n int, err error) { 34 os.Stdout.Write(p) 35 logRotator.Write(p) 36 return len(p), nil 37} 38 39// Loggers per subsystem. A single backend logger is created and all subsytem 40// loggers created from it will write to the backend. When adding new 41// subsystems, add the subsystem logger variable here and to the 42// subsystemLoggers map. 43// 44// Loggers can not be used before the log rotator has been initialized with a 45// log file. This must be performed early during application startup by calling 46// initLogRotator. 47var ( 48 // backendLog is the logging backend used to create all subsystem loggers. 49 // The backend must not be used before the log rotator has been initialized, 50 // or data races and/or nil pointer dereferences will occur. 51 backendLog = btclog.NewBackend(logWriter{}) 52 53 // logRotator is one of the logging outputs. It should be closed on 54 // application shutdown. 55 logRotator *rotator.Rotator 56 57 adxrLog = backendLog.Logger("ADXR") 58 amgrLog = backendLog.Logger("AMGR") 59 cmgrLog = backendLog.Logger("CMGR") 60 bcdbLog = backendLog.Logger("BCDB") 61 btcdLog = backendLog.Logger("BTCD") 62 chanLog = backendLog.Logger("CHAN") 63 discLog = backendLog.Logger("DISC") 64 indxLog = backendLog.Logger("INDX") 65 minrLog = backendLog.Logger("MINR") 66 peerLog = backendLog.Logger("PEER") 67 rpcsLog = backendLog.Logger("RPCS") 68 scrpLog = backendLog.Logger("SCRP") 69 srvrLog = backendLog.Logger("SRVR") 70 syncLog = backendLog.Logger("SYNC") 71 txmpLog = backendLog.Logger("TXMP") 72) 73 74// Initialize package-global logger variables. 75func init() { 76 addrmgr.UseLogger(amgrLog) 77 connmgr.UseLogger(cmgrLog) 78 database.UseLogger(bcdbLog) 79 blockchain.UseLogger(chanLog) 80 indexers.UseLogger(indxLog) 81 mining.UseLogger(minrLog) 82 cpuminer.UseLogger(minrLog) 83 peer.UseLogger(peerLog) 84 txscript.UseLogger(scrpLog) 85 netsync.UseLogger(syncLog) 86 mempool.UseLogger(txmpLog) 87} 88 89// subsystemLoggers maps each subsystem identifier to its associated logger. 90var subsystemLoggers = map[string]btclog.Logger{ 91 "ADXR": adxrLog, 92 "AMGR": amgrLog, 93 "CMGR": cmgrLog, 94 "BCDB": bcdbLog, 95 "BTCD": btcdLog, 96 "CHAN": chanLog, 97 "DISC": discLog, 98 "INDX": indxLog, 99 "MINR": minrLog, 100 "PEER": peerLog, 101 "RPCS": rpcsLog, 102 "SCRP": scrpLog, 103 "SRVR": srvrLog, 104 "SYNC": syncLog, 105 "TXMP": txmpLog, 106} 107 108// initLogRotator initializes the logging rotater to write logs to logFile and 109// create roll files in the same directory. It must be called before the 110// package-global log rotater variables are used. 111func initLogRotator(logFile string) { 112 logDir, _ := filepath.Split(logFile) 113 err := os.MkdirAll(logDir, 0700) 114 if err != nil { 115 fmt.Fprintf(os.Stderr, "failed to create log directory: %v\n", err) 116 os.Exit(1) 117 } 118 r, err := rotator.New(logFile, 10*1024, false, 3) 119 if err != nil { 120 fmt.Fprintf(os.Stderr, "failed to create file rotator: %v\n", err) 121 os.Exit(1) 122 } 123 124 logRotator = r 125} 126 127// setLogLevel sets the logging level for provided subsystem. Invalid 128// subsystems are ignored. Uninitialized subsystems are dynamically created as 129// needed. 130func setLogLevel(subsystemID string, logLevel string) { 131 // Ignore invalid subsystems. 132 logger, ok := subsystemLoggers[subsystemID] 133 if !ok { 134 return 135 } 136 137 // Defaults to info if the log level is invalid. 138 level, _ := btclog.LevelFromString(logLevel) 139 logger.SetLevel(level) 140} 141 142// setLogLevels sets the log level for all subsystem loggers to the passed 143// level. It also dynamically creates the subsystem loggers as needed, so it 144// can be used to initialize the logging system. 145func setLogLevels(logLevel string) { 146 // Configure all sub-systems with the new logging level. Dynamically 147 // create loggers as needed. 148 for subsystemID := range subsystemLoggers { 149 setLogLevel(subsystemID, logLevel) 150 } 151} 152 153// directionString is a helper function that returns a string that represents 154// the direction of a connection (inbound or outbound). 155func directionString(inbound bool) string { 156 if inbound { 157 return "inbound" 158 } 159 return "outbound" 160} 161 162// pickNoun returns the singular or plural form of a noun depending 163// on the count n. 164func pickNoun(n uint64, singular, plural string) string { 165 if n == 1 { 166 return singular 167 } 168 return plural 169} 170