如何将日志写入文件


108

我正在尝试使用Go写入日志文件。

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

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
}

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


2
如果您在Linux上部署程序,则只需将日志写入std输出,然后将输出通过管道传输至以下文件:./program 2>&1 | 发球logs.txt。在其他系统中必须有其他方式。
nvcnvn

Answers:


165

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")

基于Go文档,os.Open()不能用于log.SetOutput,因为它会打开文件“供阅读:”

func Open

func Open(name string) (file *File, err error) Open打开命名文件以供读取。如果成功,则可以使用返回文件上的方法进行读取;关联的文件描述符具有mode O_RDONLY。如果有错误,它将是类型*PathError

编辑

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


9
在检查err为零之前,请勿延迟关闭!
Volker

在所有情况下关闭iirc都不是真正有害的活动。但是,并非所有类型都正确。
达斯汀

2
@Dustin f可能是nil,这将导致恐慌。因此,err建议在延迟呼叫之前进行检查。
nemo 2013年

@Allison会解释为什么Open不配合log.SetOutput
nemo 2013年

1
更安全的权限是0644甚至0664,以允许用户读/写,用户和组读/写,并且在两种情况下均不允许所有人写。
乔纳森

39

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

./app 2>> logfile

另请参阅:http : //12factor.net/logs


当您想守护事物时,将不是一个好习惯,尤其是使用start-tsop-daemon
Shrey

3
@Shrey Systemd可以轻松处理日志记录以及启停功能。
WarGasm

尽管这不是一个好习惯,但这是我一直在Golang中寻找的日志类型。感谢您分享!
上瘾

Windows下有类似的东西吗?
surfmuggle's

就像$ cd /etc/systemd/system $ sudo vi app.service ExecStart=/bin/bash -c 'sudo go run main.go >> /home/ubuntu/go/src/html_menu_1/logfile' 我没工作Ubuntu 18.04.3
藤泽凉介

20

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

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")

7

这对我有用

  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)
    }
    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()))
      
      }

6

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

覆盖到文件

./binaryapp > binaryapp.log

附加到文件

./binaryapp >> binaryapp.log

将stderr覆盖到文件中

./binaryapp &> binaryapp.error.log

将stderr附加到文件中

./binaryapp &>> binalyapp.error.log

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


很高兴知道,我们如何覆盖stderr进行记录。
不可能的

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

}

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!!!")
}

嘿@CostaHuang,请留下详细的反馈。谢谢
openwonk

@CostaHuang,我只运行了我的代码段,它可以工作。
openwonk

嗨@openwonk,我再次测试过,它在我的计算机上不起作用。我的版本是 go version go1.10.2 windows/amd64,您的名字是?
哥斯达黎加黄

@CostaHuang,我只是运行了与您相同的示例。该示例假定您已经设置了文件夹结构。有很简单的方法可以检查这一点,但是我的示例目标是说明写入日志文件相对简单。将您的代码更改为outfile, _ = os.Create("my.log"),它将按预期工作。
openwonk

您的代码有效。我正在使用outfile, _ = os.Create("./path/to/my.log")。我以某种方式期望代码将创建path/to文件夹和my.log文件,但是显然没有用。我建议您将答案修改为outfile, _ = os.Create("./my.log")。这样,我们就清楚知道它正在当前文件夹中创建日志。
哥斯达黎加黄

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)
}

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


0

我正在将日志写入每天生成的文件(每天生成一个日志文件)。这种方法对我来说很好:

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()”方法,用于从文件的完整路径获取文件名。和“ LogServer()”方法用于创建格式化的日志语句(包含:文件名,行号,日志级别,错误语句等。)


0

为了帮助其他人,我创建了一个基本的日志函数来处理两种情况下的日志记录,如果您希望将输出输出到stdout,然后打开debug,它会直接执行switch标志,以便您选择输出。

func myLog(msg ...interface{}) {
    defer func() { r := recover(); if r != nil { fmt.Print("Error detected logging:", r) } }()
    if conf.DEBUG {
        fmt.Println(msg)
    } else {
        logfile, err := os.OpenFile(conf.LOGDIR+"/"+conf.AppName+".log", os.O_RDWR | os.O_CREATE | os.O_APPEND,0666)
        if !checkErr(err) {
            log.SetOutput(logfile)
            log.Println(msg)
        }
        defer logfile.Close()
    }
}




0

也许这会对您有所帮助(如果存在日志文件,请使用它;如果不存在,请创建它):

package main

import (
    "flag"
    "log"
    "os"
)
//Se declara la variable Log. Esta será usada para registrar los eventos.
var (
    Log *log.Logger = Loggerx()
)

func Loggerx() *log.Logger {
    LOG_FILE_LOCATION := os.Getenv("LOG_FILE_LOCATION")
        //En el caso que la variable de entorno exista, el sistema usa la configuración del docker.
    if LOG_FILE_LOCATION == "" {
        LOG_FILE_LOCATION = "../logs/" + APP_NAME + ".log"
    } else {
        LOG_FILE_LOCATION = LOG_FILE_LOCATION + APP_NAME + ".log"
    }
    flag.Parse()
        //Si el archivo existe se rehusa, es decir, no elimina el archivo log y crea uno nuevo.
    if _, err := os.Stat(LOG_FILE_LOCATION); os.IsNotExist(err) {
        file, err1 := os.Create(LOG_FILE_LOCATION)
        if err1 != nil {
            panic(err1)
        }
                //si no existe,se crea uno nuevo.
        return log.New(file, "", log.Ldate|log.Ltime|log.Lshortfile)
    } else {
                //si existe se rehusa.
        file, err := os.OpenFile(LOG_FILE_LOCATION, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0666)
        if err != nil {
            panic(err)
        }
        return log.New(file, "", log.Ldate|log.Ltime|log.Lshortfile)
    }
}

有关更多详细信息:https : //su9.co/9BAE74B

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.