github.com/btcsuite/btcd@v0.24.0/log.go (about) 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 6 package main 7 8 import ( 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. 31 type logWriter struct{} 32 33 func (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. 47 var ( 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. 75 func 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. 90 var 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. 111 func 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. 130 func 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. 145 func 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). 155 func 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. 164 func pickNoun(n uint64, singular, plural string) string { 165 if n == 1 { 166 return singular 167 } 168 return plural 169 }