Go / Golang write log to file

I am trying to write to a log file using Golang.

I tried several approaches, all of which failed. This is what I tried:

func TestLogging(t *testing.T) { if !FileExists("logfile") { CreateFile("logfile") } f, err := os.Open("logfile") if err != nil { t.Fatalf("error: %v", err) } // attempt #1 log.SetOutput(io.MultiWriter(os.Stderr, f)) log.Println("hello, logfile") // attempt #2 log.SetOutput(io.Writer(f)) log.Println("hello, logfile") // attempt #3 log.SetOutput(f) log.Println("hello, logfile") } func FileExists(name string) bool { if _, err := os.Stat(name); err != nil { if os.IsNotExist(err) { return false } } return true } func CreateFile(name string) error { fo, err := os.Create(name) if err != nil { return err } defer func() { fo.Close() }() return nil } 

A log file is created, but nothing is ever printed or added to it. Why?

+86
logging go
Nov 13 '13 at 22:30
source share
10 answers

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 os.Open() , os.Open() cannot work for log.SetOutput because it opens the file "for reading:"

func Open

func Open(name string) (file *File, err error) Open opens a named file for reading. If successful, the methods on the returned file can be used for reading; the corresponding file descriptor is in O_RDONLY mode. If there is an error, it will be of type *PathError .

EDIT

defer f.Close() moved to after checking if err != nil

+145
Nov 13 '13 at 22:56
source share

I prefer the simplicity and flexibility of the application recommendation for 12 factors for logging. To add a log file, you can use shell redirection. The default logger in Go writes to stderr (2).

 ./app 2>> logfile 

See also: http://12factor.net/logs

+29
Jul 30 '16 at 15:21
source share

I usually print logs on screen and write to a file. Hope this helps someone.

 f, err := os.OpenFile("/tmp/orders.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) if err != nil { log.Fatalf("error opening file: %v", err) } defer f.Close() wrt := io.MultiWriter(os.Stdout, f) log.SetOutput(wrt) log.Println(" Orders API Called") 
+15
Aug 01 '18 at 7:56
source share

It works for me

  • created a package called logger.go

     package logger import ( "flag" "os" "log" "go/build" ) var ( Log *log.Logger ) func init() { // set location of log file var logpath = build.Default.GOPATH + "/src/chat/logger/info.log" flag.Parse() var file, err1 = os.Create(logpath) if err1 != nil { panic(err1) } Log = log.New(file, "", log.LstdFlags|log.Lshortfile) Log.Println("LogFile : " + logpath) } 
    1. import the package wherever you want to register the main.go file

       package main import ( "logger" ) const ( VERSION = "0.13" ) func main() { // time to use our logger, print version, processID and number of running process logger.Log.Printf("Server v%s pid=%d started with processes: %d", VERSION, os.Getpid(),runtime.GOMAXPROCS(runtime.NumCPU())) } 
+6
Nov 06 '17 at 14:01
source share

The default logger in Go writes to stderr (2). file redirection

 import ( "syscall" "os" ) func main(){ fErr, err = os.OpenFile("Errfile", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600) syscall.Dup2(int(fErr.Fd()), 1) /* -- stdout */ syscall.Dup2(int(fErr.Fd()), 2) /* -- stderr */ } 
+4
Mar 13 '17 at 13:07 on
source share

Declare the top in your global var so that all your processes can access if necessary.

 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!!!") } 
+4
May 2 '18 at 3:36
source share

If you are running a binary on a Linux machine, you can use a shell script.

rewrite to file

 ./binaryapp > binaryapp.log 

add to file

 ./binaryapp >> binaryapp.log 

overwrite stderr to file

 ./binaryapp &> binaryapp.error.log 

add stderr to file

 ./binaryapp &>> binalyapp.error.log 

this can be more dynamic using the shell script file.

+2
Nov 24 '18 at 13:52
source share

I write logs to files that are generated daily (one log file is generated per day). This approach works well 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 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 } 

The "shorttenFilePath ()" method used to get the file name from the full path to the file. and the LogServer () method is used to create a formatted log statement (contains: file name, line number, log level, error statement, etc.)

0
Mar 21 '19 at 9:48
source share

Based on the answers of Allison and Deepak, I started using logrus, and I really liked 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 delay f.Close () in the main function

0
Aug 30 '19 at 0:02
source share
 import ( "os/exec" ) func main() { // check error here... exec.Command("/bin/sh", "-c", "echo "+err.Error()+" >> log.log").Run() } 
-2
Sep 29 '17 at 12:38 on
source share



All Articles