Logs JSON output.

This commit is contained in:
Miroslav Šedivý 2022-03-07 10:05:02 +00:00
parent f32e7e7075
commit d108343ced
3 changed files with 133 additions and 59 deletions

View File

@ -34,49 +34,10 @@ func init() {
rootConfig := config.Root{} rootConfig := config.Root{}
cobra.OnInitialize(func() { cobra.OnInitialize(func() {
//////
// logs
//////
console := zerolog.ConsoleWriter{Out: os.Stdout}
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
zerolog.SetGlobalLevel(zerolog.InfoLevel)
logs := viper.GetBool("logs")
if !logs {
log.Logger = log.Output(console)
} else {
logsPath := filepath.Join(".", "logs")
if runtime.GOOS == "linux" {
logsPath = "/var/log/neko"
}
if _, err := os.Stat(logsPath); os.IsNotExist(err) {
_ = os.Mkdir(logsPath, os.ModePerm)
}
latest := filepath.Join(logsPath, "neko-latest.log")
if _, err := os.Stat(latest); err == nil {
err = os.Rename(latest, filepath.Join(logsPath, "neko."+time.Now().Format("2006-01-02T15-04-05Z07-00")+".log"))
if err != nil {
log.Panic().Err(err).Msg("failed to rotate log file")
}
}
logf, err := os.OpenFile(latest, os.O_RDWR|os.O_CREATE, 0666)
if err != nil {
log.Panic().Err(err).Msg("failed to create log file")
}
logger := diode.NewWriter(logf, 1000, 10*time.Millisecond, func(missed int) {
fmt.Printf("logger dropped %d messages", missed)
})
log.Logger = log.Output(io.MultiWriter(console, logger))
}
////// //////
// configs // configs
////// //////
config := viper.GetString("config") // Use config file from the flag. config := viper.GetString("config") // Use config file from the flag.
if config == "" { if config == "" {
config = os.Getenv("NEKO_CONFIG") // Use config file from the environment variable. config = os.Getenv("NEKO_CONFIG") // Use config file from the environment variable.
@ -97,26 +58,81 @@ func init() {
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
viper.AutomaticEnv() // read in environment variables that match viper.AutomaticEnv() // read in environment variables that match
// read config values
err := viper.ReadInConfig() err := viper.ReadInConfig()
if err != nil && config != "" { if err != nil && config != "" {
log.Err(err) panic("unable to read config file: " + err.Error())
} }
// get full config file path // get full config file path
config = viper.ConfigFileUsed() config = viper.ConfigFileUsed()
// set root config values
rootConfig.Set()
////// //////
// debug // logs
////// //////
debug := viper.GetBool("debug") var logWriter io.Writer
if debug {
zerolog.SetGlobalLevel(zerolog.DebugLevel) // log to a directory instead of stderr
if rootConfig.LogDir != "" {
if _, err := os.Stat(rootConfig.LogDir); os.IsNotExist(err) {
_ = os.Mkdir(rootConfig.LogDir, os.ModePerm)
}
latest := filepath.Join(rootConfig.LogDir, "neko-latest.log")
if _, err := os.Stat(latest); err == nil {
err = os.Rename(latest, filepath.Join(rootConfig.LogDir, "neko."+time.Now().Format("2006-01-02T15-04-05Z07-00")+".log"))
if err != nil {
panic("failed to rotate log file: " + err.Error())
}
}
logf, err := os.OpenFile(latest, os.O_RDWR|os.O_CREATE, 0666)
if err != nil {
panic("failed to open log file: " + err.Error())
}
logWriter = diode.NewWriter(logf, 1000, 10*time.Millisecond, func(missed int) {
fmt.Printf("logger dropped %d messages", missed)
})
} else {
logWriter = os.Stderr
}
// log console output instead of json
if !rootConfig.LogJson {
logWriter = zerolog.ConsoleWriter{
Out: logWriter,
NoColor: rootConfig.LogNocolor,
}
}
// save new logger output
log.Logger = log.Output(logWriter)
// set custom log level
if rootConfig.LogLevel != zerolog.NoLevel {
zerolog.SetGlobalLevel(rootConfig.LogLevel)
}
// set custom log tiem format
if rootConfig.LogTime != "" {
zerolog.TimeFieldFormat = rootConfig.LogTime
}
timeFormat := rootConfig.LogTime
if rootConfig.LogTime == zerolog.TimeFormatUnix {
timeFormat = "UNIX"
} }
logger := log.With(). logger := log.With().
Bool("debug", debug).
Bool("logs", logs).
Str("config", config). Str("config", config).
Str("log-level", zerolog.GlobalLevel().String()).
Bool("log-json", rootConfig.LogJson).
Str("log-time", timeFormat).
Str("log-dir", rootConfig.LogDir).
Logger() Logger()
if config == "" { if config == "" {
@ -128,8 +144,6 @@ func init() {
logger.Info().Msg("preflight complete with config file") logger.Info().Msg("preflight complete with config file")
} }
} }
rootConfig.Set()
}) })
if err := rootConfig.Init(root); err != nil { if err := rootConfig.Init(root); err != nil {

View File

@ -1,29 +1,58 @@
package config package config
import ( import (
"os"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
) )
type Root struct { type Root struct {
Debug bool
Logs bool
Config string Config string
LogLevel zerolog.Level
LogTime string
LogJson bool
LogNocolor bool
LogDir string
} }
func (Root) Init(cmd *cobra.Command) error { func (Root) Init(cmd *cobra.Command) error {
cmd.PersistentFlags().StringP("config", "c", "", "configuration file path")
if err := viper.BindPFlag("config", cmd.PersistentFlags().Lookup("config")); err != nil {
return err
}
// just a shortcut
cmd.PersistentFlags().BoolP("debug", "d", false, "enable debug mode") cmd.PersistentFlags().BoolP("debug", "d", false, "enable debug mode")
if err := viper.BindPFlag("debug", cmd.PersistentFlags().Lookup("debug")); err != nil { if err := viper.BindPFlag("debug", cmd.PersistentFlags().Lookup("debug")); err != nil {
return err return err
} }
cmd.PersistentFlags().BoolP("logs", "l", false, "save logs to file") cmd.PersistentFlags().String("log.level", "info", "set log level (trace, debug, info, warn, error, fatal, panic, disabled)")
if err := viper.BindPFlag("logs", cmd.PersistentFlags().Lookup("logs")); err != nil { if err := viper.BindPFlag("log.level", cmd.PersistentFlags().Lookup("log.level")); err != nil {
return err return err
} }
cmd.PersistentFlags().StringP("config", "c", "", "configuration file path") cmd.PersistentFlags().String("log.time", "unix", "time format used in logs (unix, unixms, unixmicro)")
if err := viper.BindPFlag("config", cmd.PersistentFlags().Lookup("config")); err != nil { if err := viper.BindPFlag("log.time", cmd.PersistentFlags().Lookup("log.time")); err != nil {
return err
}
cmd.PersistentFlags().Bool("log.json", false, "logs in JSON format")
if err := viper.BindPFlag("log.json", cmd.PersistentFlags().Lookup("log.json")); err != nil {
return err
}
cmd.PersistentFlags().Bool("log.nocolor", false, "no ANSI colors in non-JSON output")
if err := viper.BindPFlag("log.nocolor", cmd.PersistentFlags().Lookup("log.nocolor")); err != nil {
return err
}
cmd.PersistentFlags().String("log.dir", "", "logging directory to store logs")
if err := viper.BindPFlag("log.dir", cmd.PersistentFlags().Lookup("log.dir")); err != nil {
return err return err
} }
@ -31,7 +60,38 @@ func (Root) Init(cmd *cobra.Command) error {
} }
func (s *Root) Set() { func (s *Root) Set() {
s.Logs = viper.GetBool("logs")
s.Debug = viper.GetBool("debug")
s.Config = viper.GetString("config") s.Config = viper.GetString("config")
logLevel := viper.GetString("log.level")
level, err := zerolog.ParseLevel(logLevel)
if err != nil {
log.Warn().Msgf("unknown log level %s", logLevel)
} else {
s.LogLevel = level
}
logTime := viper.GetString("log.time")
switch logTime {
case "unix":
s.LogTime = zerolog.TimeFormatUnix
case "unixms":
s.LogTime = zerolog.TimeFormatUnixMs
case "unixmicro":
s.LogTime = zerolog.TimeFormatUnixMicro
default:
log.Warn().Msgf("unknown log time %s", logTime)
}
s.LogJson = viper.GetBool("log.json")
s.LogNocolor = viper.GetBool("log.nocolor")
s.LogDir = viper.GetString("log.dir")
if viper.GetBool("debug") && s.LogLevel != zerolog.TraceLevel {
s.LogLevel = zerolog.DebugLevel
}
// support for NO_COLOR env variable: https://no-color.org/
if os.Getenv("NO_COLOR") != "" {
s.LogNocolor = true
}
} }

View File

@ -105,7 +105,7 @@ func (manager *WebSocketManagerCtx) Start() {
manager.sessions.Broadcast(event.CONTROL_HOST, payload, nil) manager.sessions.Broadcast(event.CONTROL_HOST, payload, nil)
manager.logger.Debug(). manager.logger.Info().
Bool("has_host", payload.HasHost). Bool("has_host", payload.HasHost).
Str("host_id", payload.HostID). Str("host_id", payload.HostID).
Msg("session host changed") Msg("session host changed")
@ -117,7 +117,7 @@ func (manager *WebSocketManagerCtx) Start() {
return return
} }
manager.logger.Debug().Msg("sync clipboard") manager.logger.Info().Msg("sync clipboard")
data, err := manager.desktop.ClipboardGetText() data, err := manager.desktop.ClipboardGetText()
if err != nil { if err != nil {