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?):
|
||||
https://stackoverflow.com/a/24809646
|
||||
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
|
||||
|
||||
import (
|
||||
`log/syslog`
|
||||
`os`
|
||||
|
||||
`r00t2.io/goutils/types`
|
||||
)
|
||||
|
||||
const (
|
||||
devlog string = "/dev/log"
|
||||
logPerm os.FileMode = 0600
|
||||
logPrefix string = "GOLANG PROGRAM"
|
||||
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
|
||||
|
||||
import (
|
||||
native "log"
|
||||
"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) {
|
||||
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)
|
||||
}
|
||||
|
||||
func (l *StdLogger) GetPrefix() string {
|
||||
return l.Prefix
|
||||
func (l *StdLogger) GetPrefix() (prefix string) {
|
||||
|
||||
prefix = l.Prefix
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (l *StdLogger) Alert(s string, v ...interface{}) (err error) {
|
||||
|
@ -29,8 +29,11 @@ func (l *SystemDLogger) SetPrefix(prefix string) {
|
||||
l.Prefix = prefix
|
||||
}
|
||||
|
||||
func (l *SystemDLogger) GetPrefix() string {
|
||||
return l.Prefix
|
||||
func (l *SystemDLogger) GetPrefix() (prefix string) {
|
||||
|
||||
prefix = l.Prefix
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
// TODO: implement code line, etc.
|
||||
// https://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html
|
||||
// CODE_FILE=, CODE_LINE=, CODE_FUNC=
|
@ -58,8 +58,11 @@ func (l *SyslogLogger) SetPrefix(prefix string) {
|
||||
l.Setup()
|
||||
}
|
||||
|
||||
func (l *SyslogLogger) GetPrefix() string {
|
||||
return l.Prefix
|
||||
func (l *SyslogLogger) GetPrefix() (prefix string) {
|
||||
|
||||
prefix = l.Prefix
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
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 (
|
||||
"log"
|
||||
"log/syslog"
|
||||
"os"
|
||||
)
|
||||
|
||||
@ -22,24 +21,6 @@ type Logger interface {
|
||||
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 {
|
||||
*log.Logger
|
||||
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