// Copyright 2024 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package log /* Handles the on/off flags for things like log.Info() and log.Warn() */ /* The original log flags: log.Ldate: The date in the local time zone: YYYY/MM/DD. log.Ltime: The time in the local time zone: HH:MM:SS. log.Lmicroseconds: Microsecond resolution: HH:MM:SS.microseconds. log.Llongfile: Full file name and line number: /a/b/c/d.go:23. log.Lshortfile: Final file name element and line number: d.go:23. log.LUTC: If Ldate or Ltime is set, use UTC rather than the local time zone. log.Lmsgprefix: Move the "prefix" from the beginning of the line to before the message. log.LstdFlags: Initial values for the standard logger (Ldate | Ltime). can be set this way: myLogger.SetFlags(log.Ldate | log.Ltime) */ import ( "net/http" "sync" ) var INFO *LogFlag // toggles log.Info() var VERBOSE *LogFlag // toggles log.Verbose() var SPEW *LogFlag // toggles log.Spew() var WARN *LogFlag // toggles log.Warn() (true by default) var ERROR *LogFlag // toggles log.Warn() (true by default) var PRINTLN *LogFlag // toggles log.Println() (true by default) var always *LogFlag var allon bool = false // writeMutex protects locks the write process var flagsMutex sync.Mutex type LogFlag struct { b bool orig bool // used as the Default value. set at the time of Registration() name string // TODO: figure out what package is sending the Registration subsystem string // probably should just be forced to be the package name short string // string actually printed on each line desc string } var flags []*LogFlag var daemonMode bool var httpMode http.ResponseWriter func init() { full := "go.wit.com/log" short := "log" // internally used to bypass the possibility that all the flags are off always = new(LogFlag) always.b = true always.orig = true always.subsystem = full always.short = short always.desc = "internal only" daemonMode = false INFO = NewFlag("INFO", true, full, short, "Enable log.Info()") SPEW = NewFlag("SPEW", false, full, short, "Enable log.Spew()") WARN = NewFlag("WARN", true, full, short, "Enable log.Warn()") ERROR = NewFlag("ERROR", true, full, short, "Enable log.Error()") PRINTLN = NewFlag("PRINTLN", true, full, short, "Enable log.Println()") VERBOSE = NewFlag("VERBOSE", false, full, short, "Enable log.Verbose()") } // restores flag to it's default value func (f *LogFlag) SetDefault() { if !f.Ok() { return } f.b = f.orig } // set all the flags func SetDefaults() { flagsMutex.Lock() defer flagsMutex.Unlock() for _, f := range flags { f.SetDefault() } } // simply protects against panic() by making sure it exists. func (f *LogFlag) Ok() bool { if f == nil { return false } return true } // set all the flags func SetAll(b bool) { flagsMutex.Lock() defer flagsMutex.Unlock() allon = b for _, f := range flags { f.b = b } } // this bypasses all checks and _always_ logs the info to STDOUT // is this a bad idea? Probably not.... // TODO: returning []*LogFlag is not safe and access must be locked // but this is only used by the log debugging window at this time func ShowFlags() []*LogFlag { flagsMutex.Lock() defer flagsMutex.Unlock() for _, f := range flags { Log(always, "ShowFlags() ", "("+f.subsystem+")", f.name, "=", f.b, ":", f.desc) } return flags } // TODO, switch to this. maybe. func ProcessFlags(callback func(*LogFlag)) { flagsMutex.Lock() defer flagsMutex.Unlock() for _, f := range flags { Log(always, "ProcessFlags() run callback(f) here on", f) callback(f) } } // probably a better name than Get() // switch to this func (f *LogFlag) Bool() bool { if !f.Ok() { return false } return f.b } // returns the value of the flag func (f *LogFlag) Get() bool { if !f.Ok() { return false } return f.b } /* func (f *LogFlag) Set(b bool) { if ! f.Ok() {} f.b = b } */ // returns the name of the flag func (f *LogFlag) GetName() string { if !f.Ok() { return "" } return f.name } // returns the subsystem of the flag func (f *LogFlag) GetSubsystem() string { if !f.Ok() { return "" } return f.subsystem } // returns the description of the flag func (f *LogFlag) GetDesc() string { if !f.Ok() { return "" } return f.desc } // returns the description of the flag func (f *LogFlag) GetDefault() bool { if !f.Ok() { return false } return f.orig } // register a variable name from a subsystem // inspired by Alex Flint // set the Default value at the time of registration // this is what the current log.SetFlag() function should become func NewFlag(name string, b bool, full, short, desc string) *LogFlag { flagsMutex.Lock() defer flagsMutex.Unlock() f := new(LogFlag) // Log(always, "log.SetFlag() ", full, short, name, b) if allon { f.b = true } else { f.b = b } f.orig = b f.short = short f.subsystem = full f.name = name f.desc = desc flags = append(flags, f) return f } func (f *LogFlag) SetBool(b bool) { /* if ! f.Ok() {return} flagsMutex.Lock() defer flagsMutex.Unlock() */ Info("Set() ", "("+f.subsystem+")", f.name, "=", f.b, ":", f.desc) f.b = b Info("Set() f.b is now", f.b) }