Go/Golang将日志写入文件

All*_*n A 90 logging go

我正在尝试使用Golang写入日志文件.

我尝试了几种方法,但都失败了.这是我尝试过的:

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
}
Run Code Online (Sandbox Code Playgroud)

创建了日志文件,但没有任何内容被打印或附加到它.为什么?

All*_*n A 148

os.Open() 过去必须有不同的工作方式,但这对我有用:

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")
Run Code Online (Sandbox Code Playgroud)

基于Go文档,os.Open()无法工作log.SetOutput,因为它打开文件"for reading:"

func Open

func Open(name string) (file *File, err error) Open打开指定的文件进行阅读.如果成功,返回文件上的方法可用于读取; 关联的文件描述符具有模式O_RDONLY.如果有错误,它将是类型*PathError.

编辑

移动defer f.Close()if err != nil检查后

  • 在检查错误之前不要推迟关闭! (9认同)
  • @Dustin`f`可能是'nil',这会引起恐慌。因此,建议在推迟呼叫之前检查`err`。 (2认同)
  • 更安全的权限是 0644 甚至 0664 允许用户读/写,用户和组读/写,在这两种情况下都不允许所有人写。 (2认同)

小智 30

我更喜欢12因素app推荐的简单性和灵活性.要附加到日志文件,您可以使用shell重定向.Go中的默认记录器写入stderr(2).

./app 2>> logfile
Run Code Online (Sandbox Code Playgroud)

另见:http://12factor.net/logs

  • @Shrey Systemd可以轻松地处理日志记录以及启停功能. (3认同)

dee*_*ssn 16

通常,我会在屏幕上打印日志并写入文件。希望这对某人有帮助。

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")
Run Code Online (Sandbox Code Playgroud)


小智 6

这适合我

  1. 创建了一个名为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)
    }
    
    Run Code Online (Sandbox Code Playgroud)
    1. 将包导入到您想要记录的位置,例如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()))
      
      }
      
      Run Code Online (Sandbox Code Playgroud)

  • 据我所知,这会为“file”留下一个打开的文件描述符。(错误检查后缺少“defer file.Close()”)这是一个问题吗? (2认同)

Adz*_*mzf 6

如果您在 linux 机器上运行二进制文件,则可以使用 shell 脚本。

覆盖到文件中

./binaryapp > binaryapp.log
Run Code Online (Sandbox Code Playgroud)

追加到文件中

./binaryapp >> binaryapp.log
Run Code Online (Sandbox Code Playgroud)

将 stderr 覆盖到文件中

./binaryapp &> binaryapp.error.log
Run Code Online (Sandbox Code Playgroud)

将 stderr 附加到文件中

./binaryapp &>> binalyapp.error.log
Run Code Online (Sandbox Code Playgroud)

使用 shell 脚本文件可以更动态。


小智 5

Go 中的默认记录器写入 stderr (2)。重定向到文件

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 */

}
Run Code Online (Sandbox Code Playgroud)


ope*_*onk 5

在您的全局声明顶部,var以便您的所有流程可以在需要时访问。

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!!!")
}
Run Code Online (Sandbox Code Playgroud)


小智 5

基于 Allison 和 Deepak 的回答,我开始使用 logrus 并且非常喜欢它:

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)
}
Run Code Online (Sandbox Code Playgroud)

我在主函数中有一个 defer f.Close()