Windows Event Log, error output
Adding more Event Log support, and modifying the loggers so they return errors in their operational functions.
This commit is contained in:
@@ -3,17 +3,29 @@ package logging
|
||||
import (
|
||||
`errors`
|
||||
`fmt`
|
||||
`os`
|
||||
`os/exec`
|
||||
`syscall`
|
||||
|
||||
`golang.org/x/sys/windows/registry`
|
||||
`golang.org/x/sys/windows/svc/eventlog`
|
||||
`r00t2.io/sysutils/paths`
|
||||
)
|
||||
|
||||
// Setup sets up/configures a WinLogger and prepares it for use.
|
||||
func (l *WinLogger) Setup() {
|
||||
/*
|
||||
Setup sets up/configures a WinLogger and prepares it for use.
|
||||
This will fail with an Access Denied (the first time, at least) unless running with elevated permissions unless WinLogger.Prefix is
|
||||
a registered Event Log source.
|
||||
|
||||
var err error
|
||||
If a failure occurs while trying to open the log with the given WinLogger.Prefix ("source"), a new Event Log source will be registered.
|
||||
If WinLogger.Executable is not empty at the time of calling WinLogger.Setup (or WinLogger.ForceService is true),
|
||||
eventlog.Install will be used (with the WinLogger.ExpandKey field).
|
||||
Otherwise eventlog.InstallAsEventCreate will be used.
|
||||
*/
|
||||
func (l *WinLogger) Setup() (err error) {
|
||||
|
||||
/*
|
||||
First a sanity check on the EventIDs.
|
||||
A sanity check on the EventIDs.
|
||||
Since we use eventcreate, all Event IDs must be 1 <= eid <= 1000.
|
||||
*/
|
||||
for _, eid := range []uint32{
|
||||
@@ -26,45 +38,100 @@ func (l *WinLogger) Setup() {
|
||||
l.eids.Notice,
|
||||
l.eids.Warning,
|
||||
} {
|
||||
if !((eid <= 1000) && (1 <= eid)) {
|
||||
err = errors.New("event IDs must be between 1 and 1000 inclusive")
|
||||
panic(err)
|
||||
if !((eid <= EIDMax) && (EIDMin <= eid)) {
|
||||
err = ErrBadEid
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
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 err = l.Install(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if l.elog, err = eventlog.Open(l.Prefix); err != nil {
|
||||
panic(err)
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Install installs/registers the WinLogger Event Log interface. You most likely do not need to run this directly.
|
||||
func (l *WinLogger) Install() (err error) {
|
||||
|
||||
var exists bool
|
||||
var doNotCreate bool
|
||||
var useEventCreate bool = true
|
||||
|
||||
if doNotCreate, err = l.Exists(); err != nil {
|
||||
return
|
||||
} else if !doNotCreate {
|
||||
if l.Executable != "" {
|
||||
if l.Executable, err = exec.LookPath(l.Executable); err != nil {
|
||||
return
|
||||
}
|
||||
useEventCreate = false
|
||||
} else if l.ForceService {
|
||||
if l.Executable, err = exec.LookPath(os.Args[0]); err != nil {
|
||||
return
|
||||
}
|
||||
useEventCreate = false
|
||||
}
|
||||
if !useEventCreate {
|
||||
if exists, err = paths.RealPathExists(&l.Executable); err != nil {
|
||||
return
|
||||
} else if !exists {
|
||||
err = ErrBadBinPath
|
||||
return
|
||||
}
|
||||
if err = eventlog.Install(l.Prefix, l.Executable, l.ExpandKey, eventlog.Error|eventlog.Warning|eventlog.Info); err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if err = eventlog.InstallAsEventCreate(l.Prefix, eventlog.Error|eventlog.Warning|eventlog.Info); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
// Shutdown cleanly shuts down a WinLogger.
|
||||
func (l *WinLogger) Shutdown() {
|
||||
|
||||
var err error
|
||||
|
||||
if err = l.elog.Close(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// Remove uninstalls a registered WinLogger source.
|
||||
func (l *WinLogger) Remove() (err error) {
|
||||
|
||||
if err = eventlog.Remove(l.Prefix); err != nil {
|
||||
panic(err)
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// GetPrefix returns the prefix used by this WinLogger.
|
||||
func (l *WinLogger) GetPrefix() (prefix string) {
|
||||
/*
|
||||
Shutdown cleanly shuts down a WinLogger but keep the source registered. Use WinLogger.Remove
|
||||
(or set WinLogger.RemoveOnClose to true before calling WinLogger.Shutdown) to remove the registered source.
|
||||
*/
|
||||
func (l *WinLogger) Shutdown() (err error) {
|
||||
|
||||
if err = l.elog.Close(); err != nil {
|
||||
// TODO: check for no access or file not exists syscall errors?
|
||||
return
|
||||
}
|
||||
|
||||
if l.RemoveOnClose {
|
||||
if err = l.Remove(); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
GetPrefix returns the prefix used by this WinLogger.
|
||||
err will always be nil; it's there for interface-compat.
|
||||
*/
|
||||
func (l *WinLogger) GetPrefix() (prefix string, err error) {
|
||||
|
||||
prefix = l.Prefix
|
||||
|
||||
@@ -74,43 +141,55 @@ func (l *WinLogger) GetPrefix() (prefix string) {
|
||||
/*
|
||||
DoDebug sets the debug state of this WinLogger.
|
||||
Note that this merely acts as a *safety filter* for debug messages to avoid sensitive information being written to the log.
|
||||
err will always be nil; it's there for interface-compat.
|
||||
*/
|
||||
func (l *WinLogger) DoDebug(d bool) {
|
||||
func (l *WinLogger) DoDebug(d bool) (err error) {
|
||||
|
||||
l.EnableDebug = d
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// SetPrefix sets the prefix for this WinLogger.
|
||||
func (l *WinLogger) SetPrefix(prefix string) {
|
||||
func (l *WinLogger) SetPrefix(prefix string) (err error) {
|
||||
|
||||
var err error
|
||||
// To properly change the prefix, we need to tear down the old event log and create a new one.
|
||||
if err = l.Shutdown(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
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 = l.Setup(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = eventlog.Remove(l.Prefix); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
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.
|
||||
// Exists indicates if the WinLogger.Prefix is a registered source or not.
|
||||
func (l *WinLogger) Exists() (e bool, err error) {
|
||||
|
||||
var regKey registry.Key
|
||||
var subKey registry.Key
|
||||
|
||||
if regKey, err = registry.OpenKey(registry.LOCAL_MACHINE, eventLogRegistryKey, registry.READ); err != nil {
|
||||
return
|
||||
}
|
||||
defer regKey.Close()
|
||||
|
||||
if subKey, err = registry.OpenKey(regKey, l.Prefix, registry.READ); err != nil {
|
||||
if errors.Is(err, syscall.ERROR_FILE_NOT_FOUND) {
|
||||
e = false
|
||||
err = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
defer subKey.Close()
|
||||
|
||||
if l.elog, err = eventlog.Open(l.Prefix); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
e = true
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Alert writes an ALERT-level message to this WinLogger.
|
||||
|
||||
Reference in New Issue
Block a user