在Golang中实现一个日志文件附加器。

huangapple go评论48阅读模式
英文:

Implement a log file appender in Golang

问题

我有一个使用go-logging库(https://github.com/op/go-logging)的Golang应用程序。正确生成了一个日志文件,但是当我停止并重新启动Go应用程序时,该日志文件会被一个新的日志文件覆盖。这不是一个bug,Golang只是按照要求执行操作。但如果可能的话,我希望新的日志能够追加到现有的日志文件中。

首先,这是我的main.go的一部分代码:

package main

import (
	"utils"
	"webapp"
	"odbc"
	"constants"
	"github.com/op/go-logging"
)

var config = &Configuration{}

var log = logging.MustGetLogger("main")

func main() {
	// 加载配置文件
	utils.Load(constants.CONFIG_PATH, config)

	utils.InitLog(config)

	...
}

这是我的appUtils.go文件,其中定义了一些实用函数:

package utils

import (
	"github.com/op/go-logging"
	"os"
	"fmt"
)

func InitLog(config LOG) {
	f, err := os.Create(config.LogFile)

	backend := logging.NewLogBackend(f, "", 0)

	format := logging.MustStringFormatter(config.FORMAT)

	backendFormatter := logging.NewBackendFormatter(backend, format)

	// 只有错误和更严重的消息才会发送到backend1 logging.Level
	logging.SetBackend(backendFormatter)

	level, err := logging.LogLevel(config.LEVEL)
	if err != nil {
		logging.SetLevel(logging.ERROR, "")
	} else {
		logging.SetLevel(level, "")
	}
}

type LOG struct {
	FORMAT   string
	LEVEL    string
	LogFile  string
}

如果需要的话,我也附上了我的config.json文件的内容:

{
	"LOG": {
		"LEVEL": "DEBUG",
		"FORMAT": "%{color}%{time:15:04:05.000} %{shortfunc} => %{level:.4s} %{id:03x}%{color:reset} %{message}",
		"LogFile": "logfile.log"
	}
}

我想知道我想要的是否可行?
我已经理解问题出在这一行代码上:

f, err := os.Create(config.LogFile)

在应用程序重新启动后会创建一个新文件。
为了避免这种情况,我尝试了以下代码:

var f *os.File
if _, err := os.Stat(config.LogFile); os.IsNotExist(err) {
	f, err := os.Create(config.LogFile)
} else {
	f, err := os.OpenFile(config.LogFile, os.O_APPEND|os.O_WRONLY, 0600)
}

但是这个方法并不起作用。

如果这不可行,我应该修改我的config.json文件,以便生成文件名中包含日期和毫秒的文件,例如?

英文:

I have a Golang application which uses the go-logging library (https://github.com/op/go-logging). A log file is correctly generated but when I stop and relaunch the Go application then this logfile is overwrited by a new log file. It is not a bug, Golang does what it asked to do. But if possible I would like that the new logs be appended in the existent log file.

First, an excerpt of my main.go :

package main

import (

"utils"
"webapp"
"odbc"
"constants"
"github.com/op/go-logging"
)

var config = &Configuration{}

var log = logging.MustGetLogger("main")

func main() {

     // Load the configuration file
    utils.Load(constants.CONFIG_PATH, config)

    utils.InitLog(config.LOG)

    ...
    }

My appUtils.go where the utilitary functions are defined :

package utils

import (
"github.com/op/go-logging"
"os"
"fmt"
 )

 func InitLog(config LOG) {

 f, err := os.Create(config.LogFile)

 backend := logging.NewLogBackend(f, "", 0)

 format := logging.MustStringFormatter(config.FORMAT,)

backendFormatter := logging.NewBackendFormatter(backend, format)

// Only errors and more severe messages should be sent to backend1 logging.Level
logging.SetBackend(backendFormatter)


  level, err :=  logging.LogLevel(config.LEVEL)
  if err != nil {
	 logging.SetLevel(logging.ERROR, "")
  } else{
	logging.SetLevel( level, "")
   }
 }

type LOG struct {
  FORMAT    string
  LEVEL    string
  LogFile  string
}

If needed I also put the content of my config.json :

{
  "LOG":{
	  "LEVEL": "DEBUG",
	  "FORMAT": "%{color}%{time:15:04:05.000} %{shortfunc} => %{level:.4s} %{id:03x}%{color:reset} %{message}",
	  "LogFile": "logfile.log"
      }
 }

Is what I want feasible?
I have understood that the problem comes from this line :

 f, err := os.Create(config.LogFile)

A new file is created after a (re)launch of the application.
To avoid that I tried this :

  var f *os.File
  if _, err := os.Stat(config.LogFile); os.IsNotExist(err) {
      f, err := os.Create(config.LogFile)
  }
  else {
     f, err := os.OpenFile(config.LogFile, os.O_APPEND|os.O_WRONLY,   0600)    
  }

but it's quite bullsh*t, it does not work at all.

If it's not feasible, should I modify my config.json in order to generate files that have in their name the date with the milliseconds, for instance?

答案1

得分: 3

你的版本不起作用,因为你在if块中遮蔽了f变量。如果你先声明err并使用简单赋值,这在大多数情况下看起来是有效的。

然而,对文件进行状态检查,然后尝试创建或打开它本质上是有竞争条件的。只需在一次尝试中使用正确的标志打开它。如果你想要"只写"、"追加"和"创建",那么可以使用以下代码:

os.OpenFile(name, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0600)
英文:

Your version doesn't work because you're shadowing the f variable in the if blocks. If you declared err first and use a simple assignment, this would appear to work in most cases.

However, stat'ing a file then trying to create or open it is inherently racy. Just open it with the correct flags in one try. If you want "write only", "append", and "create", then:

os.OpenFile(name, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0600)

huangapple
  • 本文由 发表于 2016年11月23日 06:29:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/40752817.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定