I have many loggers that write to a different file in my application. I'm trying to add in the ability to truncate that file while the application is running. Here is what I have:
type Resource struct {
Logger *ResourceLogger
// other stuff pertaining to my resource...
}
func (r *Resource) SetLogger(logPath string) {
path := logPath + r.Name + ".log"
f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
log.Fatalf("Unable to open log file '%v'", path)
}
r.Logger = &ResourceLogger{log.New(f, "", log.Ldate|log.Ltime), f}
}
type ResourceLogger struct {
*log.Logger
LogFile *os.File
}
This allows me to log to many files, one per resource with ease. However, when I try to use Resource.Logger.LogFile.Truncate(0) I get an access denied error.
I take it you are working on Windows, because Windows has the habbit of locking files just like that. I would suggest that since you basically can control both log writing and truncating, you can close the file for a split second and then truncate it while there are no open file handles.
You have to use for instance a mutex to stop anyone from attempting to log anything while you are truncating, and simply re-open the log file for writing after you are done. Here's a rough example for you:
package main
import (
"log"
"os"
"sync"
)
type Resource struct {
Logger *ResourceLogger
// other stuff pertaining to my resource...
Name string
}
func (r *Resource) SetLogger(logPath string) {
path := logPath + r.Name + ".log"
f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
log.Fatalf("Unable to open log file '%v'", path)
}
r.Logger = &ResourceLogger{log.New(f, "", log.Ldate|log.Ltime), f, path, sync.Mutex{}}
}
func (r *ResourceLogger) Truncate() {
if r.logger != nil {
r.logmutex.Lock()
r.logfile.Close()
os.Truncate(r.logfilename, 0) // The file must not be open on Windows!
f, err := os.OpenFile(r.logfilename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
log.Fatalf("Unable to open log file '%v'", r.logfilename)
}
r.logger = log.New(f, "", log.Ldate|log.Ltime)
r.logfile = f
r.logmutex.Unlock()
}
}
type ResourceLogger struct {
logger *log.Logger
logfile *os.File
logfilename string
logmutex sync.Mutex
}
func (r *ResourceLogger) Println(s string) {
r.logmutex.Lock()
r.logger.Println(s)
r.logmutex.Unlock()
}
func main() {
r := Resource{}
r.Name = "jeejee"
r.SetLogger("")
r.Logger.Println("test one")
for {
r.Logger.Println("more logging")
r.Logger.Truncate()
}
}