github.com/safing/portbase@v0.19.5/log/input.go (about) 1 package log 2 3 import ( 4 "fmt" 5 "runtime" 6 "strings" 7 "sync/atomic" 8 "time" 9 ) 10 11 var ( 12 warnLogLines = new(uint64) 13 errLogLines = new(uint64) 14 critLogLines = new(uint64) 15 ) 16 17 func log(level Severity, msg string, tracer *ContextTracer) { 18 if !started.IsSet() { 19 // a bit resource intense, but keeps logs before logging started. 20 // TODO: create option to disable logging 21 go func() { 22 <-startedSignal 23 log(level, msg, tracer) 24 }() 25 return 26 } 27 28 // get time 29 now := time.Now() 30 31 // get file and line 32 _, file, line, ok := runtime.Caller(2) 33 if !ok { 34 file = "" 35 line = 0 36 } else { 37 if len(file) > 3 { 38 file = file[:len(file)-3] 39 } else { 40 file = "" 41 } 42 } 43 44 // check if level is enabled for file or generally 45 if pkgLevelsActive.IsSet() { 46 pathSegments := strings.Split(file, "/") 47 if len(pathSegments) < 2 { 48 // file too short for package levels 49 return 50 } 51 pkgLevelsLock.Lock() 52 severity, ok := pkgLevels[pathSegments[len(pathSegments)-2]] 53 pkgLevelsLock.Unlock() 54 if ok { 55 if level < severity { 56 return 57 } 58 } else { 59 // no package level set, check against global level 60 if uint32(level) < atomic.LoadUint32(logLevel) { 61 return 62 } 63 } 64 } else if uint32(level) < atomic.LoadUint32(logLevel) { 65 // no package levels set, check against global level 66 return 67 } 68 69 // create log object 70 log := &logLine{ 71 msg: msg, 72 tracer: tracer, 73 level: level, 74 timestamp: now, 75 file: file, 76 line: line, 77 } 78 79 // send log to processing 80 select { 81 case logBuffer <- log: 82 default: 83 forceEmptyingLoop: 84 // force empty buffer until we can send to it 85 for { 86 select { 87 case forceEmptyingOfBuffer <- struct{}{}: 88 case logBuffer <- log: 89 break forceEmptyingLoop 90 } 91 } 92 } 93 94 // wake up writer if necessary 95 if logsWaitingFlag.SetToIf(false, true) { 96 select { 97 case logsWaiting <- struct{}{}: 98 default: 99 } 100 } 101 } 102 103 func fastcheck(level Severity) bool { 104 if pkgLevelsActive.IsSet() { 105 return true 106 } 107 if uint32(level) >= atomic.LoadUint32(logLevel) { 108 return true 109 } 110 return false 111 } 112 113 // Trace is used to log tiny steps. Log traces to context if you can! 114 func Trace(msg string) { 115 if fastcheck(TraceLevel) { 116 log(TraceLevel, msg, nil) 117 } 118 } 119 120 // Tracef is used to log tiny steps. Log traces to context if you can! 121 func Tracef(format string, things ...interface{}) { 122 if fastcheck(TraceLevel) { 123 log(TraceLevel, fmt.Sprintf(format, things...), nil) 124 } 125 } 126 127 // Debug is used to log minor errors or unexpected events. These occurrences are usually not worth mentioning in itself, but they might hint at a bigger problem. 128 func Debug(msg string) { 129 if fastcheck(DebugLevel) { 130 log(DebugLevel, msg, nil) 131 } 132 } 133 134 // Debugf is used to log minor errors or unexpected events. These occurrences are usually not worth mentioning in itself, but they might hint at a bigger problem. 135 func Debugf(format string, things ...interface{}) { 136 if fastcheck(DebugLevel) { 137 log(DebugLevel, fmt.Sprintf(format, things...), nil) 138 } 139 } 140 141 // Info is used to log mildly significant events. Should be used to inform about somewhat bigger or user affecting events that happen. 142 func Info(msg string) { 143 if fastcheck(InfoLevel) { 144 log(InfoLevel, msg, nil) 145 } 146 } 147 148 // Infof is used to log mildly significant events. Should be used to inform about somewhat bigger or user affecting events that happen. 149 func Infof(format string, things ...interface{}) { 150 if fastcheck(InfoLevel) { 151 log(InfoLevel, fmt.Sprintf(format, things...), nil) 152 } 153 } 154 155 // Warning is used to log (potentially) bad events, but nothing broke (even a little) and there is no need to panic yet. 156 func Warning(msg string) { 157 atomic.AddUint64(warnLogLines, 1) 158 if fastcheck(WarningLevel) { 159 log(WarningLevel, msg, nil) 160 } 161 } 162 163 // Warningf is used to log (potentially) bad events, but nothing broke (even a little) and there is no need to panic yet. 164 func Warningf(format string, things ...interface{}) { 165 atomic.AddUint64(warnLogLines, 1) 166 if fastcheck(WarningLevel) { 167 log(WarningLevel, fmt.Sprintf(format, things...), nil) 168 } 169 } 170 171 // Error is used to log errors that break or impair functionality. The task/process may have to be aborted and tried again later. The system is still operational. Maybe User/Admin should be informed. 172 func Error(msg string) { 173 atomic.AddUint64(errLogLines, 1) 174 if fastcheck(ErrorLevel) { 175 log(ErrorLevel, msg, nil) 176 } 177 } 178 179 // Errorf is used to log errors that break or impair functionality. The task/process may have to be aborted and tried again later. The system is still operational. 180 func Errorf(format string, things ...interface{}) { 181 atomic.AddUint64(errLogLines, 1) 182 if fastcheck(ErrorLevel) { 183 log(ErrorLevel, fmt.Sprintf(format, things...), nil) 184 } 185 } 186 187 // Critical is used to log events that completely break the system. Operation cannot continue. User/Admin must be informed. 188 func Critical(msg string) { 189 atomic.AddUint64(critLogLines, 1) 190 if fastcheck(CriticalLevel) { 191 log(CriticalLevel, msg, nil) 192 } 193 } 194 195 // Criticalf is used to log events that completely break the system. Operation cannot continue. User/Admin must be informed. 196 func Criticalf(format string, things ...interface{}) { 197 atomic.AddUint64(critLogLines, 1) 198 if fastcheck(CriticalLevel) { 199 log(CriticalLevel, fmt.Sprintf(format, things...), nil) 200 } 201 } 202 203 // TotalWarningLogLines returns the total amount of warning log lines since 204 // start of the program. 205 func TotalWarningLogLines() uint64 { 206 return atomic.LoadUint64(warnLogLines) 207 } 208 209 // TotalErrorLogLines returns the total amount of error log lines since start 210 // of the program. 211 func TotalErrorLogLines() uint64 { 212 return atomic.LoadUint64(errLogLines) 213 } 214 215 // TotalCriticalLogLines returns the total amount of critical log lines since 216 // start of the program. 217 func TotalCriticalLogLines() uint64 { 218 return atomic.LoadUint64(critLogLines) 219 }