From 52c23ffd5d49e5f15919aaeb8b59e7e379316e79 Mon Sep 17 00:00:00 2001 From: selfdenial Date: Mon, 5 Jun 2023 20:46:42 -0600 Subject: [PATCH] Introduce 2 new daemon logging options: LogUTC & LogMicro. --- daemon/default-config.json | 2 ++ daemon/log/log.go | 43 +++++++++++++++++++++++++++- daemon/main.go | 9 +++++- daemon/ui/client.go | 2 ++ daemon/ui/config.go | 2 ++ ui/opensnitch/dialogs/preferences.py | 8 ++++++ ui/opensnitch/res/preferences.ui | 34 ++++++++++++++++++++++ ui/tests/dialogs/__init__.py | 2 ++ ui/tests/dialogs/test_preferences.py | 4 +++ 9 files changed, 104 insertions(+), 2 deletions(-) diff --git a/daemon/default-config.json b/daemon/default-config.json index 31760ecc..4c461a77 100644 --- a/daemon/default-config.json +++ b/daemon/default-config.json @@ -9,6 +9,8 @@ "InterceptUnknown": false, "ProcMonitorMethod": "ebpf", "LogLevel": 2, + "LogUTC": true, + "LogMicro": false, "Firewall": "nftables", "Stats": { "MaxEvents": 150, diff --git a/daemon/log/log.go b/daemon/log/log.go index 493f8e5a..de58301d 100644 --- a/daemon/log/log.go +++ b/daemon/log/log.go @@ -49,6 +49,8 @@ var ( StdoutFile = "/dev/stdout" DateFormat = "2006-01-02 15:04:05" MinLevel = INFO + LogUTC = true + LogMicro = false mutex = &sync.RWMutex{} labels = map[int]string{ @@ -129,6 +131,36 @@ func GetLogLevel() int { return MinLevel } +// SetLogUTC configures UTC timestamps +func SetLogUTC(newLogUTC bool) { + mutex.Lock() + defer mutex.Unlock() + LogUTC = newLogUTC +} + +// GetLogUTC returns the current config. +func GetLogUTC() bool { + mutex.Lock() + defer mutex.Unlock() + + return LogUTC +} + +// SetLogMicro configures microsecond timestamps +func SetLogMicro(newLogMicro bool) { + mutex.Lock() + defer mutex.Unlock() + LogMicro = newLogMicro +} + +// GetLogMicro returns the current config. +func GetLogMicro() bool { + mutex.Lock() + defer mutex.Unlock() + + return LogMicro +} + // Log prints out a text with the given color and format func Log(level int, format string, args ...interface{}) { mutex.Lock() @@ -136,7 +168,16 @@ func Log(level int, format string, args ...interface{}) { if level >= MinLevel { label := labels[level] color := colors[level] - when := time.Now().UTC().Format(DateFormat) + + datefmt := DateFormat + + if LogMicro == true { + datefmt = DateFormat + ".000000" + } + when := time.Now().UTC().Format(datefmt) + if LogUTC == false { + when = time.Now().Local().Format(datefmt) + } what := fmt.Sprintf(format, args...) if strings.HasSuffix(what, "\n") == false { diff --git a/daemon/main.go b/daemon/main.go index 264af87f..da85e333 100644 --- a/daemon/main.go +++ b/daemon/main.go @@ -58,6 +58,8 @@ var ( checkRequirements = false procmonMethod = "" logFile = "" + logUTC = true + logMicro = false rulesPath = "rules" noLiveReload = false queueNum = 0 @@ -101,6 +103,8 @@ func init() { flag.BoolVar(&noLiveReload, "no-live-reload", debug, "Disable rules live reloading.") flag.StringVar(&logFile, "log-file", logFile, "Write logs to this file instead of the standard output.") + flag.BoolVar(&logUTC, "log-utc", logUTC, "Write logs output with UTC timezone (enabled by default).") + flag.BoolVar(&logMicro, "log-micro", logMicro, "Write logs output with microsecond timestamp (disabled by default).") flag.BoolVar(&debug, "debug", debug, "Enable debug level logs.") flag.BoolVar(&warning, "warning", warning, "Enable warning level logs.") flag.BoolVar(&important, "important", important, "Enable important level logs.") @@ -111,7 +115,7 @@ func init() { } func overwriteLogging() bool { - return debug || warning || important || errorlog || logFile != "" + return debug || warning || important || errorlog || logFile != "" || logUTC || logMicro } func setupLogging() { @@ -128,6 +132,9 @@ func setupLogging() { log.SetLogLevel(log.INFO) } + log.SetLogUTC(logUTC) + log.SetLogMicro(logMicro) + var logFileToUse string if logFile == "" { logFileToUse = log.StdoutFile diff --git a/daemon/ui/client.go b/daemon/ui/client.go index 25d247c0..926cf4e1 100644 --- a/daemon/ui/client.go +++ b/daemon/ui/client.go @@ -48,6 +48,8 @@ type Config struct { InterceptUnknown bool `json:"InterceptUnknown"` ProcMonitorMethod string `json:"ProcMonitorMethod"` LogLevel *uint32 `json:"LogLevel"` + LogUTC bool `json:"LogUTC"` + LogMicro bool `json:"LogMicro"` Firewall string `json:"Firewall"` Stats statistics.StatsConfig `json:"Stats"` } diff --git a/daemon/ui/config.go b/daemon/ui/config.go index b536dec4..3f50bae0 100644 --- a/daemon/ui/config.go +++ b/daemon/ui/config.go @@ -77,6 +77,8 @@ func (c *Client) loadConfiguration(rawConfig []byte) bool { if config.LogLevel != nil { log.SetLogLevel(int(*config.LogLevel)) } + log.SetLogUTC(config.LogUTC) + log.SetLogMicro(config.LogMicro) if config.Server.LogFile != "" { log.Close() log.OpenFile(config.Server.LogFile) diff --git a/ui/opensnitch/dialogs/preferences.py b/ui/opensnitch/dialogs/preferences.py index e0d69713..0402ea8d 100644 --- a/ui/opensnitch/dialogs/preferences.py +++ b/ui/opensnitch/dialogs/preferences.py @@ -143,6 +143,8 @@ class PreferencesDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]): self.comboNodeMonitorMethod.currentIndexChanged.connect(self._cb_node_needs_update) self.comboNodeLogLevel.currentIndexChanged.connect(self._cb_node_needs_update) self.comboNodeLogFile.currentIndexChanged.connect(self._cb_node_needs_update) + self.checkNodeLogUTC.clicked.connect(self._cb_node_needs_update) + self.checkNodeLogMicro.clicked.connect(self._cb_node_needs_update) self.comboNodeAddress.currentTextChanged.connect(self._cb_node_needs_update) self.checkInterceptUnknown.clicked.connect(self._cb_node_needs_update) self.checkApplyToNodes.clicked.connect(self._cb_node_needs_update) @@ -273,6 +275,8 @@ class PreferencesDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]): self.comboNodeMonitorMethod.setCurrentText(node_config['ProcMonitorMethod']) self.checkInterceptUnknown.setChecked(node_config['InterceptUnknown']) self.comboNodeLogLevel.setCurrentIndex(int(node_config['LogLevel'])) + self.checkNodeLogUTC.setChecked(node_config['LogUTC']) + self.checkNodeLogMicro.setChecked(node_config['LogMicro']) if node_config.get('Server') != None: self.comboNodeAddress.setEnabled(True) @@ -306,6 +310,8 @@ class PreferencesDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]): node_config['DefaultDuration'] = node_duration node_config['ProcMonitorMethod'] = self.comboNodeMonitorMethod.currentText() node_config['LogLevel'] = self.comboNodeLogLevel.currentIndex() + node_config['LogUTC'] = self.checkNodeLogUTC.isChecked() + node_config['LogMicro'] = self.checkNodeLogMicro.isChecked() node_config['InterceptUnknown'] = self.checkInterceptUnknown.isChecked() if node_config.get('Server') != None: @@ -351,6 +357,8 @@ class PreferencesDialog(QtWidgets.QDialog, uic.loadUiType(DIALOG_UI_PATH)[0]): self.comboNodeMonitorMethod.setCurrentIndex(0) self.checkInterceptUnknown.setChecked(False) self.comboNodeLogLevel.setCurrentIndex(0) + self.checkNodeLogUTC.setChecked(True) + self.checkNodeLogMicro.setChecked(False) self.labelNodeName.setText("") self.labelNodeVersion.setText("") diff --git a/ui/opensnitch/res/preferences.ui b/ui/opensnitch/res/preferences.ui index 1c6d58cb..e9446df4 100644 --- a/ui/opensnitch/res/preferences.ui +++ b/ui/opensnitch/res/preferences.ui @@ -857,6 +857,20 @@ Temporary rules will still be valid, and you can use them when prompted to allow + + + + + + + + + + + + + + @@ -1002,6 +1016,26 @@ Temporary rules will still be valid, and you can use them when prompted to allow + + + + <html><head/><body><p>If checked, OpenSnitch will use the UTC timezone for timestamps.</p></body></html> + + + Log UTC timestamps + + + + + + + <html><head/><body><p>If checked, OpenSnitch will log timestamp microseconds.</p></body></html> + + + Log timestamp microseconds + + + diff --git a/ui/tests/dialogs/__init__.py b/ui/tests/dialogs/__init__.py index 25d79707..c562095a 100644 --- a/ui/tests/dialogs/__init__.py +++ b/ui/tests/dialogs/__init__.py @@ -20,6 +20,8 @@ class ClientConfig: "InterceptUnknown": false, "ProcMonitorMethod": "ebpf", "LogLevel": 0, + "LogUTC": true, + "LogMicro": false, "Firewall": "iptables", "Stats": { "MaxEvents": 150, diff --git a/ui/tests/dialogs/test_preferences.py b/ui/tests/dialogs/test_preferences.py index 6d4bc2ff..62607b1a 100644 --- a/ui/tests/dialogs/test_preferences.py +++ b/ui/tests/dialogs/test_preferences.py @@ -72,6 +72,8 @@ class TestPreferences(): self.prefs.comboNodeAction.setCurrentIndex(Config.ACTION_ALLOW_IDX) self.prefs.comboNodeMonitorMethod.setCurrentIndex(2) self.prefs.comboNodeLogLevel.setCurrentIndex(5) + self.prefs.checkNodeLogUTC.setChecked(False) + self.prefs.checkNodeLogMicro.setChecked(True) self.prefs.checkInterceptUnknown.setChecked(True) self.prefs.tabWidget.setCurrentIndex(self.prefs.TAB_NODES) self.prefs._node_needs_update = True @@ -84,6 +86,8 @@ class TestPreferences(): assert conf['InterceptUnknown'] == True assert conf['ProcMonitorMethod'] == "audit" assert conf['LogLevel'] == 5 + assert conf['LogUTC'] == False + assert conf['LogMicro'] == True assert conf['DefaultAction'] == "allow" # TODO: click on the QMessageDialog