github.com/hyperledger/burrow@v0.34.5-0.20220512172541-77f09336001d/logging/logconfig/config.go (about) 1 package logconfig 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 8 "github.com/eapache/channels" 9 "github.com/go-kit/kit/log" 10 "github.com/hyperledger/burrow/logging" 11 12 "github.com/BurntSushi/toml" 13 "github.com/hyperledger/burrow/logging/loggers" 14 ) 15 16 type LoggingConfig struct { 17 RootSink *SinkConfig `toml:",omitempty"` 18 // Trace debug is very noisy - mostly from Tendermint 19 Trace bool 20 // Send to a channel - will not affect progress if logging graph is intensive but output will lag and some logs 21 // may be missed in shutdown 22 NonBlocking bool 23 } 24 25 // For encoding a top-level '[logging]' TOML table 26 type LoggingConfigWrapper struct { 27 Logging *LoggingConfig `toml:",omitempty"` 28 } 29 30 func DefaultNodeLoggingConfig() *LoggingConfig { 31 // Output only Burrow messages on stdout 32 return &LoggingConfig{ 33 RootSink: Sink(). 34 SetOutput(StdoutOutput().SetFormat(loggers.JSONFormat)), 35 } 36 } 37 38 // Provide a defeault logging config 39 func New() *LoggingConfig { 40 return &LoggingConfig{ 41 NonBlocking: false, 42 RootSink: Sink().SetOutput(StderrOutput().SetFormat(JSONFormat)), 43 } 44 } 45 46 func (lc *LoggingConfig) WithTrace() *LoggingConfig { 47 lc.Trace = true 48 return lc 49 } 50 51 func (lc *LoggingConfig) None() *LoggingConfig { 52 lc.RootSink = nil 53 return lc 54 } 55 56 func (lc *LoggingConfig) Root(configure func(sink *SinkConfig) *SinkConfig) *LoggingConfig { 57 lc.RootSink = configure(Sink()) 58 return lc 59 } 60 61 // Returns the TOML for a top-level logging config wrapped with [logging] 62 func (lc *LoggingConfig) RootTOMLString() string { 63 return TOMLString(LoggingConfigWrapper{lc}) 64 } 65 66 func (lc *LoggingConfig) TOMLString() string { 67 return TOMLString(lc) 68 } 69 70 func (lc *LoggingConfig) RootJSONString() string { 71 return JSONString(LoggingConfigWrapper{lc}) 72 } 73 74 func (lc *LoggingConfig) JSONString() string { 75 return JSONString(lc) 76 } 77 78 func (lc *LoggingConfig) MustLogger() *logging.Logger { 79 logger, err := lc.Logger() 80 if err != nil { 81 panic(err) 82 } 83 return logger 84 } 85 86 // Obtain a logger from this LoggingConfig 87 func (lc *LoggingConfig) Logger() (*logging.Logger, error) { 88 outputLogger, errCh, err := newLogger(lc) 89 if err != nil { 90 return nil, err 91 } 92 logger := logging.NewLogger(outputLogger) 93 if !lc.Trace { 94 logger.Trace = log.NewNopLogger() 95 } 96 go func() { 97 err := <-errCh.Out() 98 if err != nil { 99 fmt.Printf("Logging error: %v", err) 100 } 101 }() 102 return logger, nil 103 } 104 105 // Hot swap logging config by replacing output loggers built from this LoggingConfig 106 func (lc *LoggingConfig) UpdateLogger(logger *logging.Logger) (channels.Channel, error) { 107 outputLogger, errCh, err := newLogger(lc) 108 if err != nil { 109 return channels.NewDeadChannel(), err 110 } 111 logger.SwapOutput(outputLogger) 112 return errCh, nil 113 } 114 115 // Helpers 116 func newLogger(loggingConfig *LoggingConfig) (log.Logger, channels.Channel, error) { 117 outputLogger, _, err := loggingConfig.RootSink.BuildLogger() 118 if err != nil { 119 return nil, nil, err 120 } 121 var errCh channels.Channel = channels.NewDeadChannel() 122 var logger log.Logger = loggers.NewBurrowFormatLogger(outputLogger) 123 if loggingConfig.NonBlocking { 124 logger, errCh = loggers.NonBlockingLogger(logger) 125 return logger, errCh, nil 126 } 127 return logger, errCh, err 128 } 129 130 func TOMLString(v interface{}) string { 131 buf := new(bytes.Buffer) 132 encoder := toml.NewEncoder(buf) 133 err := encoder.Encode(v) 134 if err != nil { 135 // Seems like a reasonable compromise to make the string function clean 136 return fmt.Sprintf("Error encoding TOML: %s", err) 137 } 138 return buf.String() 139 } 140 141 func JSONString(v interface{}) string { 142 bs, err := json.MarshalIndent(v, "", "\t") 143 if err != nil { 144 return fmt.Sprintf("Error encoding JSON: %s", err) 145 } 146 return string(bs) 147 }