gitee.com/mysnapcore/mysnapd@v0.1.0/logger/logger.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2014,2015,2017 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package logger 21 22 import ( 23 "bytes" 24 "fmt" 25 "io" 26 "log" 27 "os" 28 "sync" 29 "time" 30 31 "gitee.com/mysnapcore/mysnapd/osutil" 32 ) 33 34 // A Logger is a fairly minimal logging tool. 35 type Logger interface { 36 // Notice is for messages that the user should see 37 Notice(msg string) 38 // Debug is for messages that the user should be able to find if they're debugging something 39 Debug(msg string) 40 } 41 42 const ( 43 // DefaultFlags are passed to the default console log.Logger 44 DefaultFlags = log.Ldate | log.Ltime | log.Lmicroseconds | log.Lshortfile 45 ) 46 47 type nullLogger struct{} 48 49 func (nullLogger) Notice(string) {} 50 func (nullLogger) Debug(string) {} 51 52 // NullLogger is a logger that does nothing 53 var NullLogger = nullLogger{} 54 55 var ( 56 logger Logger = NullLogger 57 lock sync.Mutex 58 ) 59 60 // Panicf notifies the user and then panics 61 func Panicf(format string, v ...interface{}) { 62 msg := fmt.Sprintf(format, v...) 63 64 lock.Lock() 65 defer lock.Unlock() 66 67 logger.Notice("PANIC " + msg) 68 panic(msg) 69 } 70 71 // Noticef notifies the user of something 72 func Noticef(format string, v ...interface{}) { 73 msg := fmt.Sprintf(format, v...) 74 75 lock.Lock() 76 defer lock.Unlock() 77 78 logger.Notice(msg) 79 } 80 81 // Debugf records something in the debug log 82 func Debugf(format string, v ...interface{}) { 83 msg := fmt.Sprintf(format, v...) 84 85 lock.Lock() 86 defer lock.Unlock() 87 88 logger.Debug(msg) 89 } 90 91 // MockLogger replaces the exiting logger with a buffer and returns 92 // the log buffer and a restore function. 93 func MockLogger() (buf *bytes.Buffer, restore func()) { 94 buf = &bytes.Buffer{} 95 oldLogger := logger 96 l, err := New(buf, DefaultFlags) 97 if err != nil { 98 panic(err) 99 } 100 SetLogger(l) 101 return buf, func() { 102 SetLogger(oldLogger) 103 } 104 } 105 106 // WithLoggerLock invokes f with the global logger lock, useful for 107 // tests involving goroutines with MockLogger. 108 func WithLoggerLock(f func()) { 109 lock.Lock() 110 defer lock.Unlock() 111 112 f() 113 } 114 115 // SetLogger sets the global logger to the given one 116 func SetLogger(l Logger) { 117 lock.Lock() 118 defer lock.Unlock() 119 120 logger = l 121 } 122 123 type Log struct { 124 log *log.Logger 125 126 debug bool 127 } 128 129 // Debug only prints if SNAPD_DEBUG is set 130 func (l *Log) Debug(msg string) { 131 if l.debug || osutil.GetenvBool("SNAPD_DEBUG") { 132 l.log.Output(3, "DEBUG: "+msg) 133 } 134 } 135 136 // Notice alerts the user about something, as well as putting it syslog 137 func (l *Log) Notice(msg string) { 138 l.log.Output(3, msg) 139 } 140 141 // New creates a log.Logger using the given io.Writer and flag. 142 func New(w io.Writer, flag int) (Logger, error) { 143 logger := &Log{ 144 log: log.New(w, "", flag), 145 debug: debugEnabledOnKernelCmdline(), 146 } 147 return logger, nil 148 } 149 150 // SimpleSetup creates the default (console) logger 151 func SimpleSetup() error { 152 flags := log.Lshortfile 153 if term := os.Getenv("TERM"); term != "" { 154 // snapd is probably not running under systemd 155 flags = DefaultFlags 156 } 157 l, err := New(os.Stderr, flags) 158 if err == nil { 159 SetLogger(l) 160 } 161 return err 162 } 163 164 // used to force testing of the kernel command line parsing 165 var procCmdlineUseDefaultMockInTests = true 166 167 // TODO: consider generalizing this to snapdenv and having it used by 168 // other places that consider SNAPD_DEBUG 169 func debugEnabledOnKernelCmdline() bool { 170 // if this is called during tests, always ignore it so we don't have to mock 171 // the /proc/cmdline for every test that ends up using a logger 172 if osutil.IsTestBinary() && procCmdlineUseDefaultMockInTests { 173 return false 174 } 175 m, _ := osutil.KernelCommandLineKeyValues("snapd.debug") 176 return m["snapd.debug"] == "1" 177 } 178 179 var timeNow = time.Now 180 181 // StartupStageTimestamp produce snap startup timings message. 182 func StartupStageTimestamp(stage string) { 183 now := timeNow() 184 Debugf(`-- snap startup {"stage":"%s", "time":"%v.%06d"}`, 185 stage, now.Unix(), (now.UnixNano()/1e3)%1e6) 186 }