英文:
How to write log to file
问题
我正在尝试使用Go语言写入日志文件。
我尝试了几种方法,但都失败了。以下是我尝试过的方法:
func TestLogging(t *testing.T) {
if !FileExists("logfile") {
CreateFile("logfile")
}
f, err := os.Open("logfile")
if err != nil {
t.Fatalf("error: %v", err)
}
// 尝试 #1
log.SetOutput(io.MultiWriter(os.Stderr, f))
log.Println("hello, logfile")
// 尝试 #2
log.SetOutput(io.Writer(f))
log.Println("hello, logfile")
// 尝试 #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
}
日志文件被创建了,但是没有任何内容被打印或追加到其中。为什么会这样呢?
英文:
I'm trying to write to a log file with Go.
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
得分: 215
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
打开指定的文件以供读取。如果成功,返回的文件上的方法可用于读取;关联的文件描述符具有O_RDONLY
模式。如果出现错误,它将是*PathError
类型的。
编辑
将defer f.Close()
移到if err != nil
检查之后。
英文:
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
得分: 54
我更喜欢12因素应用程序对于日志记录的简洁性和灵活性建议。要追加到日志文件中,可以使用shell重定向。Go语言中的默认日志记录器写入到stderr(2)。
./app 2>> logfile
参考链接:http://12factor.net/logs
英文:
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
得分: 42
我通常会将日志打印到屏幕上,并同时写入文件。希望这对某人有所帮助。
f, err := os.OpenFile("/tmp/orders.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
log.Fatalf("打开文件时出错:%v", err)
}
defer f.Close()
wrt := io.MultiWriter(os.Stdout, f)
log.SetOutput(wrt)
log.Println("调用了订单 API")
英文:
I usually print the logs on screen and write into a file as well. Hope this helps someone.
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")
答案4
得分: 12
这对我来说没问题。
- 创建一个名为logger.go的包
package logger
import (
"flag"
"os"
"log"
"go/build"
)
var (
Log *log.Logger
)
func init() {
// 设置日志文件的位置
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)
}
- 在需要记录日志的地方导入该包,例如main.go
package main
import (
"logger"
)
const (
VERSION = "0.13"
)
func main() {
// 使用我们的日志记录器,打印版本、进程ID和正在运行的进程数
logger.Log.Printf("Server v%s pid=%d started with processes: %d", VERSION, os.Getpid(), runtime.GOMAXPROCS(runtime.NumCPU()))
}
英文:
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
得分: 10
如果你在Linux机器上运行二进制文件,你可以使用shell脚本。
覆盖写入文件:
./binaryapp > binaryapp.log
追加写入文件:
./binaryapp >> binaryapp.log
覆盖写入标准错误到文件:
./binaryapp &> binaryapp.error.log
追加写入标准错误到文件:
./binaryapp &>> binaryapp.error.log
使用shell脚本文件可以使其更加动态。
英文:
If you run binary on linux machine you could use shell script.
overwrite into a file
./binaryapp > binaryapp.log
append into a file
./binaryapp >> binaryapp.log
overwrite stderr into a file
./binaryapp &> binaryapp.error.log
append stderr into a file
./binaryapp &>> binalyapp.error.log
it can be more dynamic using shell script file.
答案6
得分: 6
在全局var
中声明,以便所有进程都可以访问(如果需要)。
package main
import (
"log"
"os"
)
var (
outfile, _ = os.Create("path/to/my.log") // 根据你的需求更新路径
l = log.New(outfile, "", 0)
)
func main() {
l.Println("hello, log!!!")
}
英文:
Declare up top in your global var
so all your processes can access if needed.
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!!!")
}
答案7
得分: 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 */
}
英文:
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 */
}
答案8
得分: 5
根据Allison和Deepak的回答,我开始使用logrus,并且非常喜欢它:
var log = logrus.New()
func init() {
// 同时输出到控制台和文件
f, err := os.OpenFile("crawler.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
log.Fatalf("打开文件时发生错误: %v", err)
}
wrt := io.MultiWriter(os.Stdout, f)
log.SetOutput(wrt)
}
在主函数中我有一个 `defer f.Close()`。
英文:
Building on Allison and Deepak's answer, I started using logrus and really like it:
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)
}
I have a defer f.Close() in the main function
答案9
得分: 0
我正在将日志写入文件中,这些文件是每天生成的(每天生成一个日志文件)。这种方法对我来说很有效:
var (
serverLogger *log.Logger
)
func init() {
// 设置日志文件的位置
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 将日志记录到服务器的日志文件中
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 将文件路径缩短为 a/b/c/d.go 到 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()" 方法用于创建一个格式化的日志语句(包含:文件名、行号、日志级别、错误语句等)。
英文:
I'm writing logs to the files, which are generate on daily basis (per day one log file is getting generated). This approach is working fine for me :
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()" method used to get the name of the file from full path of file. and "LogServer()" method is used to create a formatted log statement (contains : filename, line number, log level, error statement etc...)
答案10
得分: 0
为了帮助他人,我创建了一个基本的日志函数来处理日志记录,无论是将输出发送到标准输出(stdout)还是将调试(debug)打开,都可以直接进行开关切换,以便选择输出方式。
func myLog(msg ...interface{}) {
defer func() { r := recover(); if r != nil { fmt.Print("检测到错误日志:", 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()
}
}
希望这能帮到你!
英文:
To help others, I create a basic log function to handle the logging in both cases, if you want the output to stdout, then turn debug on, its straight forward to do a switch flag so you can choose your output.
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()
}
}
</details>
# 答案11
**得分**: 0
也许这会对你有所帮助(如果日志文件存在,则使用它,如果不存在则创建):
```go
package main
import (
"flag"
"log"
"os"
)
// 声明Log变量,用于记录事件。
var (
Log *log.Logger = Loggerx()
)
func Loggerx() *log.Logger {
LOG_FILE_LOCATION := os.Getenv("LOG_FILE_LOCATION")
// 如果环境变量存在,则使用Docker的配置。
if LOG_FILE_LOCATION == "" {
LOG_FILE_LOCATION = "../logs/" + APP_NAME + ".log"
} else {
LOG_FILE_LOCATION = LOG_FILE_LOCATION + APP_NAME + ".log"
}
flag.Parse()
// 如果文件不存在,则创建一个新的日志文件。
if _, err := os.Stat(LOG_FILE_LOCATION); os.IsNotExist(err) {
file, err1 := os.Create(LOG_FILE_LOCATION)
if err1 != nil {
panic(err1)
}
// 如果文件不存在,则创建一个新的日志文件。
return log.New(file, "", log.Ldate|log.Ltime|log.Lshortfile)
} else {
// 如果文件存在,则重用它。
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
英文:
maybe this will help you (if the log file exists use it, if it does not exist create it):
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)
}
}
For more detail: https://su9.co/9BAE74B
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论