safing-portmaster/base/log/input.go
Daniel Hååvi 80664d1a27
Restructure modules ()
* Move portbase into monorepo

* Add new simple module mgr

* [WIP] Switch to new simple module mgr

* Add StateMgr and more worker variants

* [WIP] Switch more modules

* [WIP] Switch more modules

* [WIP] swtich more modules

* [WIP] switch all SPN modules

* [WIP] switch all service modules

* [WIP] Convert all workers to the new module system

* [WIP] add new task system to module manager

* [WIP] Add second take for scheduling workers

* [WIP] Add FIXME for bugs in new scheduler

* [WIP] Add minor improvements to scheduler

* [WIP] Add new worker scheduler

* [WIP] Fix more bug related to new module system

* [WIP] Fix start handing of the new module system

* [WIP] Improve startup process

* [WIP] Fix minor issues

* [WIP] Fix missing subsystem in settings

* [WIP] Initialize managers in constructor

* [WIP] Move module event initialization to constrictors

* [WIP] Fix setting for enabling and disabling the SPN module

* [WIP] Move API registeration into module construction

* [WIP] Update states mgr for all modules

* [WIP] Add CmdLine operation support

* Add state helper methods to module group and instance

* Add notification and module status handling to status package

* Fix starting issues

* Remove pilot widget and update security lock to new status data

* Remove debug logs

* Improve http server shutdown

* Add workaround for cleanly shutting down firewall+netquery

* Improve logging

* Add syncing states with notifications for new module system

* Improve starting, stopping, shutdown; resolve FIXMEs/TODOs

* [WIP] Fix most unit tests

* Review new module system and fix minor issues

* Push shutdown and restart events again via API

* Set sleep mode via interface

* Update example/template module

* [WIP] Fix spn/cabin unit test

* Remove deprecated UI elements

* Make log output more similar for the logging transition phase

* Switch spn hub and observer cmds to new module system

* Fix log sources

* Make worker mgr less error prone

* Fix tests and minor issues

* Fix observation hub

* Improve shutdown and restart handling

* Split up big connection.go source file

* Move varint and dsd packages to structures repo

* Improve expansion test

* Fix linter warnings

* Fix interception module on windows

* Fix linter errors

---------

Co-authored-by: Vladimir Stoilov <vladimir@safing.io>
2024-08-09 18:15:48 +03:00

219 lines
5.6 KiB
Go

package log
import (
"fmt"
"runtime"
"strings"
"sync/atomic"
"time"
)
var (
warnLogLines = new(uint64)
errLogLines = new(uint64)
critLogLines = new(uint64)
)
func log(level Severity, msg string, tracer *ContextTracer) {
if !started.IsSet() {
// a bit resource intense, but keeps logs before logging started.
// TODO: create option to disable logging
go func() {
<-startedSignal
log(level, msg, tracer)
}()
return
}
// get time
now := time.Now()
// get file and line
_, file, line, ok := runtime.Caller(2)
if !ok {
file = ""
line = 0
} else {
if len(file) > 3 {
file = file[:len(file)-3]
} else {
file = ""
}
}
// check if level is enabled for file or generally
if pkgLevelsActive.IsSet() {
pathSegments := strings.Split(file, "/")
if len(pathSegments) < 2 {
// file too short for package levels
return
}
pkgLevelsLock.Lock()
severity, ok := pkgLevels[pathSegments[len(pathSegments)-2]]
pkgLevelsLock.Unlock()
if ok {
if level < severity {
return
}
} else {
// no package level set, check against global level
if uint32(level) < atomic.LoadUint32(logLevel) {
return
}
}
} else if uint32(level) < atomic.LoadUint32(logLevel) {
// no package levels set, check against global level
return
}
// create log object
log := &logLine{
msg: msg,
tracer: tracer,
level: level,
timestamp: now,
file: file,
line: line,
}
// send log to processing
select {
case logBuffer <- log:
default:
forceEmptyingLoop:
// force empty buffer until we can send to it
for {
select {
case forceEmptyingOfBuffer <- struct{}{}:
case logBuffer <- log:
break forceEmptyingLoop
}
}
}
// wake up writer if necessary
if logsWaitingFlag.SetToIf(false, true) {
select {
case logsWaiting <- struct{}{}:
default:
}
}
}
func fastcheck(level Severity) bool {
if pkgLevelsActive.IsSet() {
return true
}
if uint32(level) >= atomic.LoadUint32(logLevel) {
return true
}
return false
}
// Trace is used to log tiny steps. Log traces to context if you can!
func Trace(msg string) {
if fastcheck(TraceLevel) {
log(TraceLevel, msg, nil)
}
}
// Tracef is used to log tiny steps. Log traces to context if you can!
func Tracef(format string, things ...interface{}) {
if fastcheck(TraceLevel) {
log(TraceLevel, fmt.Sprintf(format, things...), nil)
}
}
// 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.
func Debug(msg string) {
if fastcheck(DebugLevel) {
log(DebugLevel, msg, nil)
}
}
// 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.
func Debugf(format string, things ...interface{}) {
if fastcheck(DebugLevel) {
log(DebugLevel, fmt.Sprintf(format, things...), nil)
}
}
// Info is used to log mildly significant events. Should be used to inform about somewhat bigger or user affecting events that happen.
func Info(msg string) {
if fastcheck(InfoLevel) {
log(InfoLevel, msg, nil)
}
}
// Infof is used to log mildly significant events. Should be used to inform about somewhat bigger or user affecting events that happen.
func Infof(format string, things ...interface{}) {
if fastcheck(InfoLevel) {
log(InfoLevel, fmt.Sprintf(format, things...), nil)
}
}
// Warning is used to log (potentially) bad events, but nothing broke (even a little) and there is no need to panic yet.
func Warning(msg string) {
atomic.AddUint64(warnLogLines, 1)
if fastcheck(WarningLevel) {
log(WarningLevel, msg, nil)
}
}
// Warningf is used to log (potentially) bad events, but nothing broke (even a little) and there is no need to panic yet.
func Warningf(format string, things ...interface{}) {
atomic.AddUint64(warnLogLines, 1)
if fastcheck(WarningLevel) {
log(WarningLevel, fmt.Sprintf(format, things...), nil)
}
}
// 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.
func Error(msg string) {
atomic.AddUint64(errLogLines, 1)
if fastcheck(ErrorLevel) {
log(ErrorLevel, msg, nil)
}
}
// 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.
func Errorf(format string, things ...interface{}) {
atomic.AddUint64(errLogLines, 1)
if fastcheck(ErrorLevel) {
log(ErrorLevel, fmt.Sprintf(format, things...), nil)
}
}
// Critical is used to log events that completely break the system. Operation cannot continue. User/Admin must be informed.
func Critical(msg string) {
atomic.AddUint64(critLogLines, 1)
if fastcheck(CriticalLevel) {
log(CriticalLevel, msg, nil)
}
}
// Criticalf is used to log events that completely break the system. Operation cannot continue. User/Admin must be informed.
func Criticalf(format string, things ...interface{}) {
atomic.AddUint64(critLogLines, 1)
if fastcheck(CriticalLevel) {
log(CriticalLevel, fmt.Sprintf(format, things...), nil)
}
}
// TotalWarningLogLines returns the total amount of warning log lines since
// start of the program.
func TotalWarningLogLines() uint64 {
return atomic.LoadUint64(warnLogLines)
}
// TotalErrorLogLines returns the total amount of error log lines since start
// of the program.
func TotalErrorLogLines() uint64 {
return atomic.LoadUint64(errLogLines)
}
// TotalCriticalLogLines returns the total amount of critical log lines since
// start of the program.
func TotalCriticalLogLines() uint64 {
return atomic.LoadUint64(critLogLines)
}