Improve logger (#566)

* Improve logger

 - Try to log to jorunald if available
 - fallback to file writing if not
 - write to single file instead of appending times
 - add a locking mechanism so several processes cant write to the same
   file
 - prepend the PID of the process if we are running outside journald for
   easy tracking of grouped messages

Signed-off-by: Itxaka <itxaka@kairos.io>

* Simplify

Signed-off-by: Itxaka <itxaka@kairos.io>

---------

Signed-off-by: Itxaka <itxaka@kairos.io>
This commit is contained in:
Itxaka
2025-02-24 11:34:54 +01:00
committed by GitHub
parent c52bfb5708
commit aa62f8ba73
3 changed files with 86 additions and 31 deletions

View File

@@ -4,35 +4,48 @@ import (
"bytes"
"fmt"
"io"
"net"
"os"
"path/filepath"
"strings"
"time"
"github.com/rs/zerolog"
"github.com/rs/zerolog/journald"
)
func isJournaldAvailable() bool {
conn, err := net.Dial("unixgram", "/run/systemd/journal/socket")
if err != nil {
return false
}
defer conn.Close()
return true
}
// NewKairosLogger creates a new logger with the given name and level.
// The name is used to create a log file in /run/kairos/NAME-DATE.log and /var/log/kairos/NAME-DATE.log
// The level is used to set the log level, defaulting to info
// The log level can be overridden by setting the environment variable $NAME_DEBUG to any parseable value.
// If quiet is true, the logger will not log to the console.
func NewKairosLogger(name, level string, quiet bool) KairosLogger {
var loggers []io.Writer
var l zerolog.Level
var err error
// Add journald logger
if isJournaldAvailable() {
loggers = append(loggers, journald.NewJournalDWriter())
} else {
// Default to file logging
logName := fmt.Sprintf("%s.log", name)
_ = os.MkdirAll("/var/log/kairos/", os.ModeDir|os.ModePerm)
logFileName := filepath.Join("/var/log/kairos/", logName)
logfile, err := os.OpenFile(logFileName, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err == nil {
loggers = append(loggers, zerolog.ConsoleWriter{Out: logfile, TimeFormat: time.RFC3339, NoColor: true})
}
// Have I ever mentioned how terrible the format of time is in golang?
// Whats with this 20060102150405 format? Do anyone actually remembers that?
logName := fmt.Sprintf("%s-%s.log", name, time.Now().Format("20060102150405.0000"))
_ = os.MkdirAll("/run/kairos/", os.ModeDir|os.ModePerm)
_ = os.MkdirAll("/var/log/kairos/", os.ModeDir|os.ModePerm)
logfileRun, err := os.Create(filepath.Join("/run/kairos/", logName))
if err == nil {
loggers = append(loggers, zerolog.ConsoleWriter{Out: logfileRun, TimeFormat: time.RFC3339, NoColor: true})
}
logfileVar, err := os.Create(filepath.Join("/var/log/kairos/", logName))
if err == nil {
loggers = append(loggers, zerolog.ConsoleWriter{Out: logfileVar, TimeFormat: time.RFC3339, NoColor: true})
}
if !quiet {
@@ -61,7 +74,7 @@ func NewKairosLogger(name, level string, quiet bool) KairosLogger {
}
k := KairosLogger{
zerolog.New(multi).With().Timestamp().Logger().Level(l),
loggers,
isJournaldAvailable(),
}
return k
@@ -70,21 +83,21 @@ func NewKairosLogger(name, level string, quiet bool) KairosLogger {
func NewBufferLogger(b *bytes.Buffer) KairosLogger {
return KairosLogger{
zerolog.New(b).With().Timestamp().Logger(),
[]io.Writer{},
true,
}
}
func NewNullLogger() KairosLogger {
return KairosLogger{
zerolog.New(io.Discard).With().Timestamp().Logger(),
[]io.Writer{},
true,
}
}
// KairosLogger implements the bridge between zerolog and the logger.Interface that yip needs.
type KairosLogger struct {
zerolog.Logger
logFiles []io.Writer
journald bool // Whether we are logging to journald, to avoid the file lock
}
func (m *KairosLogger) SetLevel(level string) {
@@ -101,65 +114,105 @@ func (m KairosLogger) IsDebug() bool {
return m.Logger.GetLevel() == zerolog.DebugLevel
}
// Close Try to close all log files
func (m KairosLogger) Close() {
for _, f := range m.logFiles {
if c, ok := f.(io.Closer); ok {
_ = c.Close()
}
}
}
// Functions to implement the logger.Interface that most of our other stuff needs
func (m KairosLogger) Infof(tpl string, args ...interface{}) {
if !m.journald {
// Add the pid to the log line so searching for it is easier
tpl = fmt.Sprintf("[%v] ", os.Getpid()) + tpl
}
m.Logger.Info().Msg(fmt.Sprintf(tpl, args...))
}
func (m KairosLogger) Info(args ...interface{}) {
if !m.journald {
args = append([]interface{}{fmt.Sprintf("[%v]", os.Getpid())}, args...)
}
m.Logger.Info().Msg(fmt.Sprint(args...))
}
func (m KairosLogger) Warnf(tpl string, args ...interface{}) {
if !m.journald {
tpl = fmt.Sprintf("[%v] ", os.Getpid()) + tpl
}
m.Logger.Warn().Msg(fmt.Sprintf(tpl, args...))
}
func (m KairosLogger) Warn(args ...interface{}) {
if !m.journald {
args = append([]interface{}{fmt.Sprintf("[%v]", os.Getpid())}, args...)
}
m.Logger.Warn().Msg(fmt.Sprint(args...))
}
func (m KairosLogger) Warning(args ...interface{}) {
if !m.journald {
args = append([]interface{}{fmt.Sprintf("[%v]", os.Getpid())}, args...)
}
m.Logger.Warn().Msg(fmt.Sprint(args...))
}
func (m KairosLogger) Warningf(tpl string, args ...interface{}) {
if !m.journald {
tpl = fmt.Sprintf("[%v] ", os.Getpid()) + tpl
}
m.Logger.Warn().Msg(fmt.Sprintf(tpl, args...))
}
func (m KairosLogger) Debugf(tpl string, args ...interface{}) {
if !m.journald {
tpl = fmt.Sprintf("[%v] ", os.Getpid()) + tpl
}
m.Logger.Debug().Msg(fmt.Sprintf(tpl, args...))
}
func (m KairosLogger) Debug(args ...interface{}) {
if !m.journald {
args = append([]interface{}{fmt.Sprintf("[%v]", os.Getpid())}, args...)
}
m.Logger.Debug().Msg(fmt.Sprint(args...))
}
func (m KairosLogger) Errorf(tpl string, args ...interface{}) {
if !m.journald {
tpl = fmt.Sprintf("[%v] ", os.Getpid()) + tpl
}
m.Logger.Error().Msg(fmt.Sprintf(tpl, args...))
}
func (m KairosLogger) Error(args ...interface{}) {
if !m.journald {
args = append([]interface{}{fmt.Sprintf("[%v]", os.Getpid())}, args...)
}
m.Logger.Error().Msg(fmt.Sprint(args...))
}
func (m KairosLogger) Fatalf(tpl string, args ...interface{}) {
if !m.journald {
tpl = fmt.Sprintf("[%v] ", os.Getpid()) + tpl
}
m.Logger.Fatal().Msg(fmt.Sprintf(tpl, args...))
}
func (m KairosLogger) Fatal(args ...interface{}) {
if !m.journald {
args = append([]interface{}{fmt.Sprintf("[%v]", os.Getpid())}, args...)
}
m.Logger.Fatal().Msg(fmt.Sprint(args...))
}
func (m KairosLogger) Panicf(tpl string, args ...interface{}) {
if !m.journald {
tpl = fmt.Sprintf("[%v] ", os.Getpid()) + tpl
}
m.Logger.Panic().Msg(fmt.Sprintf(tpl, args...))
}
func (m KairosLogger) Panic(args ...interface{}) {
if !m.journald {
args = append([]interface{}{fmt.Sprintf("[%v]", os.Getpid())}, args...)
}
m.Logger.Panic().Msg(fmt.Sprint(args...))
}
func (m KairosLogger) Tracef(tpl string, args ...interface{}) {
if !m.journald {
tpl = fmt.Sprintf("[%v] ", os.Getpid()) + tpl
}
m.Logger.Trace().Msg(fmt.Sprintf(tpl, args...))
}
func (m KairosLogger) Trace(args ...interface{}) {
if !m.journald {
args = append([]interface{}{fmt.Sprintf("[%v]", os.Getpid())}, args...)
}
m.Logger.Trace().Msg(fmt.Sprint(args...))
}