可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I'm trying to write to a log file with Golang.
I have tried several approaches, all of which have failed. This is what I have 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 }
The log file gets created, but nothing ever gets printed or appended to it. Why?
回答1:
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 mode O_RDONLY. If there is an error, it will be of type *PathError.
EDIT
Moved defer f.Close() to after if err != nil check
回答2:
I prefer the simplicity and flexibility of the 12 factor app recommendation for logging. To append to 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
回答3:
The default logger in Go writes to stderr (2). redirect to file
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:
This 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) }
import the package wherever you want to log e.g main.go
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())) }
回答5:
Declare up top in your global var so all your processes can access if needed.
package main import ( "log" "os" ) var ( outfile, _ = os.Create("./logs/my.log") l = log.New(outfile, "", 0) ) func main() { l.Println("hello, log!!!") }
回答6:
import ( "os/exec" ) func main() { // check error here... exec.Command("/bin/sh", "-c", "echo "+err.Error()+" >> log.log").Run() }