英文:
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)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论