如何将日志写入文件

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

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

这对我来说没问题。

  1. 创建一个名为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)
}
  1. 在需要记录日志的地方导入该包,例如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

  1. 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)
    }
    
  2. 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 (
&quot;flag&quot;
&quot;log&quot;
&quot;os&quot;
)
//Se declara la variable Log. Esta ser&#225; usada para registrar los eventos.
var (
Log *log.Logger = Loggerx()
)
func Loggerx() *log.Logger {
LOG_FILE_LOCATION := os.Getenv(&quot;LOG_FILE_LOCATION&quot;)
//En el caso que la variable de entorno exista, el sistema usa la configuraci&#243;n del docker.
if LOG_FILE_LOCATION == &quot;&quot; {
LOG_FILE_LOCATION = &quot;../logs/&quot; + APP_NAME + &quot;.log&quot;
} else {
LOG_FILE_LOCATION = LOG_FILE_LOCATION + APP_NAME + &quot;.log&quot;
}
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, &quot;&quot;, 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, &quot;&quot;, log.Ldate|log.Ltime|log.Lshortfile)
}
}

For more detail: https://su9.co/9BAE74B

huangapple
  • 本文由 发表于 2013年11月14日 06:30:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/19965795.html
匿名

发表评论

匿名网友

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

确定