do bitmask better, add (COMPLETELY 100% EXPERIMENTAL NOT DONE YET) eventlog support to logger
This commit is contained in:
parent
d5b1d449e5
commit
3975f8b11f
46
bitmask/bitmasks.go
Normal file
46
bitmask/bitmasks.go
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
package bitmask
|
||||||
|
|
||||||
|
// MaskBit is a flag container.
|
||||||
|
type MaskBit uint8
|
||||||
|
|
||||||
|
/*
|
||||||
|
NewMaskBit is a convenience function.
|
||||||
|
It will return a MaskBit with a (referenced) value of 0, so set your consts up accordingly.
|
||||||
|
It is highly recommended to set this default as a "None" flag (separate from your iotas!)
|
||||||
|
as shown in the example.
|
||||||
|
*/
|
||||||
|
func NewMaskBit() (m *MaskBit) {
|
||||||
|
|
||||||
|
m = new(MaskBit)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasFlag is true if m has MaskBit flag set/enabled.
|
||||||
|
func (m *MaskBit) HasFlag(flag MaskBit) (r bool) {
|
||||||
|
|
||||||
|
var b MaskBit = *m
|
||||||
|
|
||||||
|
if b&flag != 0 {
|
||||||
|
r = true
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddFlag adds MaskBit flag to m.
|
||||||
|
func (m *MaskBit) AddFlag(flag MaskBit) {
|
||||||
|
*m |= flag
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClearFlag removes MaskBit flag from m.
|
||||||
|
func (m *MaskBit) ClearFlag(flag MaskBit) {
|
||||||
|
*m &= flag
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToggleFlag switches MaskBit flag in m to its inverse; if true, it is now false and vice versa.
|
||||||
|
func (m *MaskBit) ToggleFlag(flag MaskBit) {
|
||||||
|
*m ^= flag
|
||||||
|
return
|
||||||
|
}
|
45
bitmask/doc.go
Normal file
45
bitmask/doc.go
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
Package bitmask handles a flag-like opt/bitmask system.
|
||||||
|
|
||||||
|
See https://yourbasic.org/golang/bitmask-flag-set-clear/ for more information.
|
||||||
|
|
||||||
|
To use this, set constants like thus:
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"r00t2.io/goutils/bitmask"
|
||||||
|
)
|
||||||
|
|
||||||
|
const OPTNONE types.MaskBit = 0
|
||||||
|
const (
|
||||||
|
OPT1 types.MaskBit = 1 << iota
|
||||||
|
OPT2
|
||||||
|
OPT3
|
||||||
|
// ...
|
||||||
|
)
|
||||||
|
|
||||||
|
var MyMask *MaskBit
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
MyMask = types.NewMaskBit
|
||||||
|
|
||||||
|
MyMask.AddFlag(OPT1)
|
||||||
|
MyMask.AddFlag(OPT3)
|
||||||
|
|
||||||
|
_ = MyMask
|
||||||
|
}
|
||||||
|
|
||||||
|
This would return true:
|
||||||
|
|
||||||
|
MyMask.HasFlag(OPT1)
|
||||||
|
|
||||||
|
As would this:
|
||||||
|
|
||||||
|
MyMask.HasFlag(OPT3)
|
||||||
|
|
||||||
|
But this would return false:
|
||||||
|
|
||||||
|
MyMask.HasFlag(OPT2)
|
||||||
|
*/
|
||||||
|
package bitmask
|
@ -1,3 +1,11 @@
|
|||||||
- Implement code line/func/etc. (only for debug?):
|
- Implement code line/func/etc. (only for debug?):
|
||||||
https://stackoverflow.com/a/24809646
|
https://stackoverflow.com/a/24809646
|
||||||
https://golang.org/pkg/runtime/#Caller
|
https://golang.org/pkg/runtime/#Caller
|
||||||
|
|
||||||
|
- Support simultaneous writing to multiple Loggers.
|
||||||
|
|
||||||
|
- Suport remote loggers? (eventlog, syslog, systemd)
|
||||||
|
|
||||||
|
- DOCS.
|
||||||
|
|
||||||
|
- Unit/Integration tests.
|
||||||
|
@ -1,29 +1,11 @@
|
|||||||
package logging
|
package logging
|
||||||
|
|
||||||
import (
|
import (
|
||||||
`log/syslog`
|
|
||||||
`os`
|
`os`
|
||||||
|
|
||||||
`r00t2.io/goutils/types`
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
devlog string = "/dev/log"
|
|
||||||
logPerm os.FileMode = 0600
|
logPerm os.FileMode = 0600
|
||||||
logPrefix string = "GOLANG PROGRAM"
|
logPrefix string = "GOLANG PROGRAM"
|
||||||
appendFlags int = os.O_APPEND|os.O_CREATE|os.O_WRONLY
|
appendFlags int = os.O_APPEND|os.O_CREATE|os.O_WRONLY
|
||||||
syslogFacility syslog.Priority = syslog.LOG_USER
|
|
||||||
)
|
|
||||||
|
|
||||||
// Flags for logger configuration
|
|
||||||
const (
|
|
||||||
LogUndefined types.MaskBit = 1 << iota
|
|
||||||
LogJournald
|
|
||||||
LogSyslog
|
|
||||||
LogFile
|
|
||||||
LogStdout
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
defLogPaths = []string{"/var/log/golang/program.log", "~/.local/log/golang/program.log"}
|
|
||||||
)
|
)
|
||||||
|
28
logging/consts_linux.go
Normal file
28
logging/consts_linux.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package logging
|
||||||
|
|
||||||
|
import (
|
||||||
|
`log/syslog`
|
||||||
|
|
||||||
|
`r00t2.io/goutils/bitmask`
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
devlog string = "/dev/log"
|
||||||
|
syslogFacility syslog.Priority = syslog.LOG_USER
|
||||||
|
)
|
||||||
|
|
||||||
|
// Flags for logger configuration
|
||||||
|
const (
|
||||||
|
LogUndefined bitmask.MaskBit = 1 << iota
|
||||||
|
LogJournald
|
||||||
|
LogSyslog
|
||||||
|
LogFile
|
||||||
|
LogStdout
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
defLogPaths = []string{
|
||||||
|
"/var/log/golang/program.log",
|
||||||
|
"~/.local/log/golang/program.log",
|
||||||
|
}
|
||||||
|
)
|
48
logging/consts_windows.go
Normal file
48
logging/consts_windows.go
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package logging
|
||||||
|
|
||||||
|
import (
|
||||||
|
`os`
|
||||||
|
`path/filepath`
|
||||||
|
`regexp`
|
||||||
|
)
|
||||||
|
|
||||||
|
// Flags for logger configuration
|
||||||
|
const (
|
||||||
|
LogUndefined types.MaskBit = 1 << iota
|
||||||
|
LogWinLogger
|
||||||
|
LogFile
|
||||||
|
LogStdout
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
defLogPaths = []string{
|
||||||
|
filepath.Join(os.Getenv("ALLUSERSPROFILE"), "golang", "program.log"), // C:\ProgramData\log\golang\program.log
|
||||||
|
filepath.Join(os.Getenv("LOCALAPPDATA"), "log", "golang", "program.log"), // C:\Users\<username>\AppData\Local\log\golang\program.log
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
var ptrnSourceExists *regexp.Regexp = regexp.MustCompile(`registry\skey\salready\sexists$`)
|
||||||
|
|
||||||
|
// Default WinEventID
|
||||||
|
var DefaultEventID *WinEventID = &WinEventID{
|
||||||
|
Alert: EventAlert,
|
||||||
|
Crit: EventCrit,
|
||||||
|
Debug: EventDebug,
|
||||||
|
Emerg: EventEmerg,
|
||||||
|
Err: EventErr,
|
||||||
|
Info: EventInfo,
|
||||||
|
Notice: EventNotice,
|
||||||
|
Warning: EventWarning,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default Event IDs for WinEventID.
|
||||||
|
const (
|
||||||
|
EventAlert uint32 = 1 << iota
|
||||||
|
EventCrit
|
||||||
|
EventDebug
|
||||||
|
EventEmerg
|
||||||
|
EventErr
|
||||||
|
EventInfo
|
||||||
|
EventNotice
|
||||||
|
EventWarning
|
||||||
|
)
|
117
logging/funcs.go
117
logging/funcs.go
@ -1,126 +1,9 @@
|
|||||||
package logging
|
package logging
|
||||||
|
|
||||||
import (
|
import (
|
||||||
native "log"
|
|
||||||
"os"
|
"os"
|
||||||
"path"
|
|
||||||
|
|
||||||
"r00t2.io/goutils/types"
|
|
||||||
|
|
||||||
sysd "github.com/coreos/go-systemd/journal"
|
|
||||||
"r00t2.io/sysutils/paths"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
|
||||||
_ = sysd.Enabled()
|
|
||||||
_ = native.Logger{}
|
|
||||||
_ = os.Interrupt
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetLogger returns an instance of Logger that best suits your system's capabilities.
|
|
||||||
// If enableDebug is true, debug messages (which according to your program may or may not contain sensitive data) are rendered and written.
|
|
||||||
// If prefix is "\x00" (a null byte), then the default logging prefix will be used. If anything else, even an empty string,
|
|
||||||
// is specified then that will be used instead for the prefix.
|
|
||||||
// logpaths is an (optional) list of strings to use as paths to test for writing. If the file can be created/written to,
|
|
||||||
// it will be used (assuming you have no higher-level loggers available). Only the first logpaths entry that "works" will be used, later entries will be ignored.
|
|
||||||
func GetLogger(enableDebug bool, prefix string, logpaths ...string) (logger Logger, err error) {
|
|
||||||
|
|
||||||
var logPath string
|
|
||||||
var logflags types.MaskBit
|
|
||||||
|
|
||||||
// Configure system-supported logger(s).
|
|
||||||
if sysd.Enabled() {
|
|
||||||
// Use Journald.
|
|
||||||
logflags.AddFlag(LogJournald)
|
|
||||||
} else {
|
|
||||||
// If we can detect syslog, use that. If not, try to use a file logger (+ stdout).
|
|
||||||
// Last ditch, stdout.
|
|
||||||
var hasSyslog bool
|
|
||||||
var stat os.FileInfo
|
|
||||||
var devlogPath string = devlog
|
|
||||||
|
|
||||||
if hasSyslog, stat, err = paths.RealPathExistsStat(&devlogPath); hasSyslog && err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if hasSyslog && !stat.Mode().IsRegular() {
|
|
||||||
logflags.AddFlag(LogSyslog)
|
|
||||||
} else {
|
|
||||||
var exists bool
|
|
||||||
var success bool
|
|
||||||
var ckLogPaths []string
|
|
||||||
logflags.AddFlag(LogStdout)
|
|
||||||
ckLogPaths = defLogPaths
|
|
||||||
if logpaths != nil {
|
|
||||||
ckLogPaths = logpaths
|
|
||||||
}
|
|
||||||
for _, p := range ckLogPaths {
|
|
||||||
if exists, _ = paths.RealPathExists(&p); exists {
|
|
||||||
if success, err = testOpen(p); err != nil {
|
|
||||||
continue
|
|
||||||
} else if !success {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
logflags.AddFlag(LogFile)
|
|
||||||
logPath = p
|
|
||||||
break
|
|
||||||
} else {
|
|
||||||
dirPath := path.Dir(p)
|
|
||||||
if err = paths.MakeDirIfNotExist(&dirPath); err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if success, err = testOpen(p); err != nil {
|
|
||||||
continue
|
|
||||||
} else if !success {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
logflags.AddFlag(LogFile)
|
|
||||||
logPath = p
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if logflags.HasFlag(LogJournald) {
|
|
||||||
logger = &SystemDLogger{
|
|
||||||
Prefix: logPrefix,
|
|
||||||
EnableDebug: enableDebug,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if logflags.HasFlag(LogSyslog) {
|
|
||||||
logger = &SyslogLogger{
|
|
||||||
Prefix: logPrefix,
|
|
||||||
EnableDebug: enableDebug,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if logflags.HasFlag(LogFile) {
|
|
||||||
logger = &FileLogger{
|
|
||||||
StdLogger: StdLogger{
|
|
||||||
Prefix: logPrefix,
|
|
||||||
EnableDebug: enableDebug,
|
|
||||||
},
|
|
||||||
Path: logPath,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
logger = &StdLogger{
|
|
||||||
Prefix: logPrefix,
|
|
||||||
EnableDebug: enableDebug,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Setup()
|
|
||||||
if prefix != "\x00" {
|
|
||||||
logger.SetPrefix(prefix)
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Info("logger initialized of type %T with prefix %v", logger, logger.GetPrefix())
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func testOpen(path string) (success bool, err error) {
|
func testOpen(path string) (success bool, err error) {
|
||||||
var f *os.File
|
var f *os.File
|
||||||
|
|
||||||
|
123
logging/funcs_linux.go
Normal file
123
logging/funcs_linux.go
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
package logging
|
||||||
|
|
||||||
|
import (
|
||||||
|
native `log`
|
||||||
|
`os`
|
||||||
|
`path`
|
||||||
|
|
||||||
|
sysd `github.com/coreos/go-systemd/journal`
|
||||||
|
`r00t2.io/sysutils/paths`
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
_ = sysd.Enabled()
|
||||||
|
_ = native.Logger{}
|
||||||
|
_ = os.Interrupt
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
GetLogger returns an instance of Logger that best suits your system's capabilities.
|
||||||
|
If enableDebug is true, debug messages (which according to your program may or may not contain sensitive data) are rendered and written.
|
||||||
|
If prefix is "\x00" (a null byte), then the default logging prefix will be used. If anything else, even an empty string,
|
||||||
|
is specified then that will be used instead for the prefix.
|
||||||
|
logPaths is an (optional) list of strings to use as paths to test for writing. If the file can be created/written to,
|
||||||
|
it will be used (assuming you have no higher-level loggers available). Only the first logPaths entry that "works" will be used, later entries will be ignored.
|
||||||
|
*/
|
||||||
|
func GetLogger(enableDebug bool, prefix string, logPaths ...string) (logger Logger, err error) {
|
||||||
|
|
||||||
|
var logPath string
|
||||||
|
var logFlags types.MaskBit
|
||||||
|
|
||||||
|
// Configure system-supported logger(s).
|
||||||
|
if sysd.Enabled() {
|
||||||
|
// Use Journald.
|
||||||
|
logFlags.AddFlag(LogJournald)
|
||||||
|
} else {
|
||||||
|
// If we can detect syslog, use that. If not, try to use a file logger (+ stdout).
|
||||||
|
// Last ditch, stdout.
|
||||||
|
var hasSyslog bool
|
||||||
|
var stat os.FileInfo
|
||||||
|
var devlogPath string = devlog
|
||||||
|
|
||||||
|
if hasSyslog, stat, err = paths.RealPathExistsStat(&devlogPath); hasSyslog && err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if hasSyslog && !stat.Mode().IsRegular() {
|
||||||
|
logFlags.AddFlag(LogSyslog)
|
||||||
|
} else {
|
||||||
|
var exists bool
|
||||||
|
var success bool
|
||||||
|
var ckLogPaths []string
|
||||||
|
|
||||||
|
logFlags.AddFlag(LogStdout)
|
||||||
|
ckLogPaths = defLogPaths
|
||||||
|
if logPaths != nil {
|
||||||
|
ckLogPaths = logPaths
|
||||||
|
}
|
||||||
|
for _, p := range ckLogPaths {
|
||||||
|
if exists, _ = paths.RealPathExists(&p); exists {
|
||||||
|
if success, err = testOpen(p); err != nil {
|
||||||
|
continue
|
||||||
|
} else if !success {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
logFlags.AddFlag(LogFile)
|
||||||
|
logPath = p
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
dirPath := path.Dir(p)
|
||||||
|
if err = paths.MakeDirIfNotExist(&dirPath); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if success, err = testOpen(p); err != nil {
|
||||||
|
continue
|
||||||
|
} else if !success {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
logFlags.AddFlag(LogFile)
|
||||||
|
logPath = p
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if logFlags.HasFlag(LogJournald) {
|
||||||
|
logger = &SystemDLogger{
|
||||||
|
Prefix: logPrefix,
|
||||||
|
EnableDebug: enableDebug,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if logFlags.HasFlag(LogSyslog) {
|
||||||
|
logger = &SyslogLogger{
|
||||||
|
Prefix: logPrefix,
|
||||||
|
EnableDebug: enableDebug,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if logFlags.HasFlag(LogFile) {
|
||||||
|
logger = &FileLogger{
|
||||||
|
StdLogger: StdLogger{
|
||||||
|
Prefix: logPrefix,
|
||||||
|
EnableDebug: enableDebug,
|
||||||
|
},
|
||||||
|
Path: logPath,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger = &StdLogger{
|
||||||
|
Prefix: logPrefix,
|
||||||
|
EnableDebug: enableDebug,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Setup()
|
||||||
|
if prefix != "\x00" {
|
||||||
|
logger.SetPrefix(prefix)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("logger initialized of type %T with prefix %v", logger, logger.GetPrefix())
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
@ -27,8 +27,11 @@ func (l *StdLogger) SetPrefix(prefix string) {
|
|||||||
l.Logger.SetPrefix(prefix)
|
l.Logger.SetPrefix(prefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *StdLogger) GetPrefix() string {
|
func (l *StdLogger) GetPrefix() (prefix string) {
|
||||||
return l.Prefix
|
|
||||||
|
prefix = l.Prefix
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *StdLogger) Alert(s string, v ...interface{}) (err error) {
|
func (l *StdLogger) Alert(s string, v ...interface{}) (err error) {
|
||||||
|
@ -29,8 +29,11 @@ func (l *SystemDLogger) SetPrefix(prefix string) {
|
|||||||
l.Prefix = prefix
|
l.Prefix = prefix
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *SystemDLogger) GetPrefix() string {
|
func (l *SystemDLogger) GetPrefix() (prefix string) {
|
||||||
return l.Prefix
|
|
||||||
|
prefix = l.Prefix
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *SystemDLogger) Alert(s string, v ...interface{}) (err error) {
|
func (l *SystemDLogger) Alert(s string, v ...interface{}) (err error) {
|
||||||
@ -158,6 +161,7 @@ func (l *SystemDLogger) Warning(s string, v ...interface{}) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l *SystemDLogger) renderWrite(msg string, prio journal.Priority) {
|
func (l *SystemDLogger) renderWrite(msg string, prio journal.Priority) {
|
||||||
|
|
||||||
// TODO: implement code line, etc.
|
// TODO: implement code line, etc.
|
||||||
// https://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html
|
// https://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html
|
||||||
// CODE_FILE=, CODE_LINE=, CODE_FUNC=
|
// CODE_FILE=, CODE_LINE=, CODE_FUNC=
|
@ -58,8 +58,11 @@ func (l *SyslogLogger) SetPrefix(prefix string) {
|
|||||||
l.Setup()
|
l.Setup()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *SyslogLogger) GetPrefix() string {
|
func (l *SyslogLogger) GetPrefix() (prefix string) {
|
||||||
return l.Prefix
|
|
||||||
|
prefix = l.Prefix
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *SyslogLogger) Alert(s string, v ...interface{}) (err error) {
|
func (l *SyslogLogger) Alert(s string, v ...interface{}) (err error) {
|
100
logging/funcs_windows.go
Normal file
100
logging/funcs_windows.go
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
package logging
|
||||||
|
|
||||||
|
import (
|
||||||
|
`errors`
|
||||||
|
`strings`
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
GetLogger returns an instance of Logger that best suits your system's capabilities. Note that this is a VERY generalized interface to the Windows Event Log.
|
||||||
|
If you require more robust logging capabilities (e.g. custom event IDs per uniquely identifiable event),
|
||||||
|
you will want to set up your own logger (golang.org/x/sys/windows/svc/eventlog).
|
||||||
|
If enableDebug is true, debug messages (which according to your program may or may not contain sensitive data) are rendered and written (otherwise they are ignored).
|
||||||
|
A blank source will return an error as it's used as the source name. Other functions, struct fields, etc. will refer to this as the "prefix".
|
||||||
|
A pointer to a WinEventID struct may be specified for eventIDs to map extended logging levels (as Windows only supports three levels natively).
|
||||||
|
If it is nil, a default one (DefaultEventID) will be used.
|
||||||
|
logPaths is an (optional) list of strings to use as paths to test for writing. If the file can be created/written to,
|
||||||
|
it will be used (assuming you have no higher-level loggers available).
|
||||||
|
Only the first logPaths entry that "works" will be used, later entries will be ignored.
|
||||||
|
Currently this will almost always return a WinLogger until multiple logging destination support is added.
|
||||||
|
*/
|
||||||
|
func GetLogger(enableDebug bool, source string, eventIDs *WinEventID, logPaths ...string) (logger Logger, err error) {
|
||||||
|
|
||||||
|
var logPath string
|
||||||
|
var logFlags types.MaskBit
|
||||||
|
var exists bool
|
||||||
|
var success bool
|
||||||
|
var ckLogPaths []string
|
||||||
|
|
||||||
|
if strings.TrimSpace(source) == "" {
|
||||||
|
err = errors.New("invalid source for Windows logging")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure system-supported logger(s). The Windows Event Logger (should) ALWAYS be available.
|
||||||
|
logFlags.AddFlag(LogWinLogger)
|
||||||
|
if eventIDs == nil {
|
||||||
|
eventIDs = DefaultEventID
|
||||||
|
}
|
||||||
|
|
||||||
|
if logPaths != nil {
|
||||||
|
ckLogPaths = logPaths
|
||||||
|
ckLogPaths = append(ckLogPaths, defLogPaths...)
|
||||||
|
|
||||||
|
for _, p := range ckLogPaths {
|
||||||
|
if exists, _ = paths.RealPathExists(&p); exists {
|
||||||
|
if success, err = testOpen(p); err != nil {
|
||||||
|
continue
|
||||||
|
} else if !success {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
logFlags.AddFlag(LogFile)
|
||||||
|
logPath = p
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
dirPath := path.Dir(p)
|
||||||
|
if err = paths.MakeDirIfNotExist(&dirPath); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if success, err = testOpen(p); err != nil {
|
||||||
|
continue
|
||||||
|
} else if !success {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
logFlags.AddFlag(LogFile)
|
||||||
|
logPath = p
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if logFlags.HasFlag(LogWinLogger) {
|
||||||
|
logger = &WinLogger{
|
||||||
|
Prefix: source,
|
||||||
|
EnableDebug: enableDebug,
|
||||||
|
eids: eventIDs,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if logFlags.HasFlag(LogFile) {
|
||||||
|
logger = &FileLogger{
|
||||||
|
StdLogger: StdLogger{
|
||||||
|
Prefix: source,
|
||||||
|
EnableDebug: enableDebug,
|
||||||
|
},
|
||||||
|
Path: logPath,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger = &StdLogger{
|
||||||
|
Prefix: source,
|
||||||
|
EnableDebug: enableDebug,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Setup()
|
||||||
|
|
||||||
|
logger.Info("logger initialized of type %T with source %v", logger, logger.GetPrefix())
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
}
|
238
logging/funcs_winlogger_windows.go
Normal file
238
logging/funcs_winlogger_windows.go
Normal file
@ -0,0 +1,238 @@
|
|||||||
|
package logging
|
||||||
|
|
||||||
|
import (
|
||||||
|
`errors`
|
||||||
|
)
|
||||||
|
|
||||||
|
func (l *WinLogger) Setup() {
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
/*
|
||||||
|
First a sanity check on the EventIDs.
|
||||||
|
Since we use eventcreate, all Event IDs must be 1 <= eid <= 1000.
|
||||||
|
*/
|
||||||
|
for _, eid := range []uint32{
|
||||||
|
l.eids.Alert,
|
||||||
|
l.eids.Crit,
|
||||||
|
l.eids.Debug,
|
||||||
|
l.eids.Emerg,
|
||||||
|
l.eids.Err,
|
||||||
|
l.eids.Info,
|
||||||
|
l.eids.Notice,
|
||||||
|
l.eids.Warning,
|
||||||
|
} {
|
||||||
|
if !(1 <= eid <= 1000) {
|
||||||
|
err = errors.New("event IDs must be between 1 and 1000 inclusive")
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = eventlog.InstallAsEventCreate(l.Prefix, eventlog.Error|eventlog.Warning|eventlog.Info); err != nil {
|
||||||
|
if idx := ptrnSourceExists.FindStringIndex(err.Error()); idx == nil {
|
||||||
|
// It's an error we want to panic on.
|
||||||
|
panic(err)
|
||||||
|
} else {
|
||||||
|
// It already exists, so ignore the error.
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if l.elog, err = eventlog.Open(l.Prefix); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *WinLogger) Shutdown() {
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if err = l.elog.Close(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = eventlog.Remove(l.Prefix); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *WinLogger) DoDebug(d bool) {
|
||||||
|
|
||||||
|
l.EnableDebug = d
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *WinLogger) SetPrefix(prefix string) {
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
l.Prefix = prefix
|
||||||
|
|
||||||
|
// To properly change the prefix, we need to tear down the old event log and create a new one.
|
||||||
|
if err = l.elog.Close(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = eventlog.Remove(l.Prefix); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = eventlog.InstallAsEventCreate(l.Prefix, eventlog.Error|eventlog.Warning|eventlog.Info); err != nil {
|
||||||
|
if idx := ptrnSourceExists.FindStringIndex(err.Error()); idx == nil {
|
||||||
|
// It's an error we want to panic on.
|
||||||
|
panic(err)
|
||||||
|
} else {
|
||||||
|
// It already exists, so ignore the error.
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if l.elog, err = eventlog.Open(l.Prefix); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *WinLogger) GetPrefix() (prefix string) {
|
||||||
|
|
||||||
|
prefix = l.Prefix
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *WinLogger) Alert(s string, v ...interface{}) (err error) {
|
||||||
|
|
||||||
|
var msg string
|
||||||
|
|
||||||
|
if v != nil {
|
||||||
|
msg = fmt.Sprintf(s, v...)
|
||||||
|
} else {
|
||||||
|
msg = s
|
||||||
|
}
|
||||||
|
|
||||||
|
// Treat ALERT as Warning
|
||||||
|
err = l.elog.Warning(l.eids.Alert, msg)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *WinLogger) Crit(s string, v ...interface{}) (err error) {
|
||||||
|
|
||||||
|
var msg string
|
||||||
|
|
||||||
|
if v != nil {
|
||||||
|
msg = fmt.Sprintf(s, v...)
|
||||||
|
} else {
|
||||||
|
msg = s
|
||||||
|
}
|
||||||
|
|
||||||
|
// Treat CRIT as Error
|
||||||
|
err = l.elog.Error(l.eids.Crit, msg)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *WinLogger) Debug(s string, v ...interface{}) (err error) {
|
||||||
|
|
||||||
|
if !l.EnableDebug {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var msg string
|
||||||
|
|
||||||
|
if v != nil {
|
||||||
|
msg = fmt.Sprintf(s, v...)
|
||||||
|
} else {
|
||||||
|
msg = s
|
||||||
|
}
|
||||||
|
|
||||||
|
// Treat DEBUG as Info
|
||||||
|
err = l.elog.Info(l.eids.Debug, msg)
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *WinLogger) Emerg(s string, v ...interface{}) (err error) {
|
||||||
|
|
||||||
|
var msg string
|
||||||
|
|
||||||
|
if v != nil {
|
||||||
|
msg = fmt.Sprintf(s, v...)
|
||||||
|
} else {
|
||||||
|
msg = s
|
||||||
|
}
|
||||||
|
|
||||||
|
// Treat EMERG as Error
|
||||||
|
err = l.elog.Error(l.eids.Emerg, msg)
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *WinLogger) Err(s string, v ...interface{}) (err error) {
|
||||||
|
|
||||||
|
var msg string
|
||||||
|
|
||||||
|
if v != nil {
|
||||||
|
msg = fmt.Sprintf(s, v...)
|
||||||
|
} else {
|
||||||
|
msg = s
|
||||||
|
}
|
||||||
|
|
||||||
|
err = l.elog.Error(l.eids.Error, msg)
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *WinLogger) Info(s string, v ...interface{}) (err error) {
|
||||||
|
|
||||||
|
var msg string
|
||||||
|
|
||||||
|
if v != nil {
|
||||||
|
msg = fmt.Sprintf(s, v...)
|
||||||
|
} else {
|
||||||
|
msg = s
|
||||||
|
}
|
||||||
|
|
||||||
|
err = l.elog.Info(l.eids.Info, msg)
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *WinLogger) Notice(s string, v ...interface{}) (err error) {
|
||||||
|
|
||||||
|
var msg string
|
||||||
|
|
||||||
|
if v != nil {
|
||||||
|
msg = fmt.Sprintf(s, v...)
|
||||||
|
} else {
|
||||||
|
msg = s
|
||||||
|
}
|
||||||
|
|
||||||
|
// Treat NOTICE as Info
|
||||||
|
err = l.elog.Info(l.eids.Notice, msg)
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *WinLogger) Warning(s string, v ...interface{}) (err error) {
|
||||||
|
|
||||||
|
var msg string
|
||||||
|
|
||||||
|
if v != nil {
|
||||||
|
msg = fmt.Sprintf(s, v...)
|
||||||
|
} else {
|
||||||
|
msg = s
|
||||||
|
}
|
||||||
|
|
||||||
|
err = l.elog.Warning(l.eids.Warning, msg)
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
}
|
@ -2,7 +2,6 @@ package logging
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
"log/syslog"
|
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -22,24 +21,6 @@ type Logger interface {
|
|||||||
Shutdown()
|
Shutdown()
|
||||||
}
|
}
|
||||||
|
|
||||||
type SystemDLogger struct {
|
|
||||||
EnableDebug bool
|
|
||||||
Prefix string
|
|
||||||
}
|
|
||||||
|
|
||||||
type SyslogLogger struct {
|
|
||||||
EnableDebug bool
|
|
||||||
Prefix string
|
|
||||||
alert,
|
|
||||||
crit,
|
|
||||||
debug,
|
|
||||||
emerg,
|
|
||||||
err,
|
|
||||||
info,
|
|
||||||
notice,
|
|
||||||
warning *syslog.Writer
|
|
||||||
}
|
|
||||||
|
|
||||||
type StdLogger struct {
|
type StdLogger struct {
|
||||||
*log.Logger
|
*log.Logger
|
||||||
EnableDebug bool
|
EnableDebug bool
|
||||||
|
23
logging/types_linux.go
Normal file
23
logging/types_linux.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package logging
|
||||||
|
|
||||||
|
import (
|
||||||
|
`log/syslog`
|
||||||
|
)
|
||||||
|
|
||||||
|
type SystemDLogger struct {
|
||||||
|
EnableDebug bool
|
||||||
|
Prefix string
|
||||||
|
}
|
||||||
|
|
||||||
|
type SyslogLogger struct {
|
||||||
|
EnableDebug bool
|
||||||
|
Prefix string
|
||||||
|
alert,
|
||||||
|
crit,
|
||||||
|
debug,
|
||||||
|
emerg,
|
||||||
|
err,
|
||||||
|
info,
|
||||||
|
notice,
|
||||||
|
warning *syslog.Writer
|
||||||
|
}
|
23
logging/types_windows.go
Normal file
23
logging/types_windows.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package logging
|
||||||
|
|
||||||
|
import (
|
||||||
|
`golang.org/x/sys/windows/svc/eventlog`
|
||||||
|
)
|
||||||
|
|
||||||
|
type WinLogger struct {
|
||||||
|
EnableDebug bool
|
||||||
|
Prefix string
|
||||||
|
elog *eventlog.Log
|
||||||
|
eids *WinEventID
|
||||||
|
}
|
||||||
|
|
||||||
|
type WinEventID struct {
|
||||||
|
Alert,
|
||||||
|
Crit,
|
||||||
|
Debug,
|
||||||
|
Emerg,
|
||||||
|
Err,
|
||||||
|
Info,
|
||||||
|
Notice,
|
||||||
|
Warning uint32
|
||||||
|
}
|
@ -1,64 +0,0 @@
|
|||||||
package types
|
|
||||||
|
|
||||||
/*
|
|
||||||
See https://yourbasic.org/golang/bitmask-flag-set-clear/ for more information.
|
|
||||||
To use this, set constants like thus:
|
|
||||||
|
|
||||||
const (
|
|
||||||
OPT1 types.MaskBit = 1 << iota
|
|
||||||
OPT2
|
|
||||||
OPT3
|
|
||||||
// ...
|
|
||||||
)
|
|
||||||
|
|
||||||
type Object struct {
|
|
||||||
Opts BitMask
|
|
||||||
}
|
|
||||||
|
|
||||||
o := Object{
|
|
||||||
BitMask: uint8(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
o.AddFlag(OPT1)
|
|
||||||
o.AddFlag(OPT3)
|
|
||||||
|
|
||||||
|
|
||||||
This would return true:
|
|
||||||
o.HasFlag(OPT1)
|
|
||||||
As would this:
|
|
||||||
o.HasFlag(OPT3)
|
|
||||||
But this would return false:
|
|
||||||
o.HasFlag(OPT2)
|
|
||||||
|
|
||||||
*/
|
|
||||||
type BitMask interface {
|
|
||||||
HasFlag(bit MaskBit) bool
|
|
||||||
AddFlag(bit MaskBit)
|
|
||||||
ClearFlag(bit MaskBit)
|
|
||||||
ToggleFlag(bit MaskBit)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BitMasks
|
|
||||||
type MaskBit uint8
|
|
||||||
|
|
||||||
func (f MaskBit) HasFlag(flag MaskBit) (r bool) {
|
|
||||||
if f&flag != 0 {
|
|
||||||
r = true
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *MaskBit) AddFlag(flag MaskBit) {
|
|
||||||
*f |= flag
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *MaskBit) ClearFlag(flag MaskBit) {
|
|
||||||
*f &= flag
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *MaskBit) ToggleFlag(flag MaskBit) {
|
|
||||||
*f ^= flag
|
|
||||||
return
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user