I\'m trying to write to a log file with Go.
I have tried several approaches, all of which have failed. This is what I have tried:
func TestLogging(t
os.Open()
must have worked differently in the past, but this works for me:
f, err := os.OpenFile("testlogfile", os.O_RDWR | os.O_CREATE | os.O_APPEND, 0666)
if err != nil {
log.Fatalf("error opening file: %v", err)
}
defer f.Close()
log.SetOutput(f)
log.Println("This is a test log entry")
Based on the Go docs, os.Open()
can't work for log.SetOutput
, because it opens the file "for reading:"
func Open
func Open(name string) (file *File, err error)
Open
opens the named file for reading. If successful, methods on the returned file can be used for reading; the associated file descriptor has modeO_RDONLY
. If there is an error, it will be of type*PathError
.
EDIT
Moved defer f.Close()
to after if err != nil
check
Building on Allison and Deepak's answer, I started using logrus and really like it:
var log = logrus.New()
func init() {
// log to console and file
f, err := os.OpenFile("crawler.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
log.Fatalf("error opening file: %v", err)
}
wrt := io.MultiWriter(os.Stdout, f)
log.SetOutput(wrt)
}
I have a defer f.Close() in the main function
Declare up top in your global var
so all your processes can access if needed.
package main
import (
"log"
"os"
)
var (
outfile, _ = os.Create("path/to/my.log") // update path for your needs
l = log.New(outfile, "", 0)
)
func main() {
l.Println("hello, log!!!")
}
If you run binary on linux machine you could use shell script.
overwrite into a file
./binaryapp > binaryapp.log
append into a file
./binaryapp >> binaryapp.log
overwrite stderr into a file
./binaryapp &> binaryapp.error.log
append stderr into a file
./binaryapp &>> binalyapp.error.log
it can be more dynamic using shell script file.
I'm writing logs to the files, which are generate on daily basis (per day one log file is getting generated). This approach is working fine for me :
var (
serverLogger *log.Logger
)
func init() {
// set location of log file
date := time.Now().Format("2006-01-02")
var logpath = os.Getenv(constant.XDirectoryPath) + constant.LogFilePath + date + constant.LogFileExtension
os.MkdirAll(os.Getenv(constant.XDirectoryPath)+constant.LogFilePath, os.ModePerm)
flag.Parse()
var file, err1 = os.OpenFile(logpath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err1 != nil {
panic(err1)
}
mw := io.MultiWriter(os.Stdout, file)
serverLogger = log.New(mw, constant.Empty, log.LstdFlags)
serverLogger.Println("LogFile : " + logpath)
}
// LogServer logs to server's log file
func LogServer(logLevel enum.LogLevel, message string) {
_, file, no, ok := runtime.Caller(1)
logLineData := "logger_server.go"
if ok {
file = shortenFilePath(file)
logLineData = fmt.Sprintf(file + constant.ColonWithSpace + strconv.Itoa(no) + constant.HyphenWithSpace)
}
serverLogger.Println(logLineData + logLevel.String() + constant.HyphenWithSpace + message)
}
// ShortenFilePath Shortens file path to a/b/c/d.go tp d.go
func shortenFilePath(file string) string {
short := file
for i := len(file) - 1; i > 0; i-- {
if file[i] == constant.ForwardSlash {
short = file[i+1:]
break
}
}
file = short
return file
}
"shortenFilePath()" method used to get the name of the file from full path of file. and "LogServer()" method is used to create a formatted log statement (contains : filename, line number, log level, error statement etc...)