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  }