如何将日志写入文件

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

How to write log to file

问题

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

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

  1. func TestLogging(t *testing.T) {
  2. if !FileExists("logfile") {
  3. CreateFile("logfile")
  4. }
  5. f, err := os.Open("logfile")
  6. if err != nil {
  7. t.Fatalf("error: %v", err)
  8. }
  9. // 尝试 #1
  10. log.SetOutput(io.MultiWriter(os.Stderr, f))
  11. log.Println("hello, logfile")
  12. // 尝试 #2
  13. log.SetOutput(io.Writer(f))
  14. log.Println("hello, logfile")
  15. // 尝试 #3
  16. log.SetOutput(f)
  17. log.Println("hello, logfile")
  18. }
  19. func FileExists(name string) bool {
  20. if _, err := os.Stat(name); err != nil {
  21. if os.IsNotExist(err) {
  22. return false
  23. }
  24. }
  25. return true
  26. }
  27. func CreateFile(name string) error {
  28. fo, err := os.Create(name)
  29. if err != nil {
  30. return err
  31. }
  32. defer func() {
  33. fo.Close()
  34. }()
  35. return nil
  36. }

日志文件被创建了,但是没有任何内容被打印或追加到其中。为什么会这样呢?

英文:

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:

  1. func TestLogging(t *testing.T) {
  2. if !FileExists("logfile") {
  3. CreateFile("logfile")
  4. }
  5. f, err := os.Open("logfile")
  6. if err != nil {
  7. t.Fatalf("error: %v", err)
  8. }
  9. // attempt #1
  10. log.SetOutput(io.MultiWriter(os.Stderr, f))
  11. log.Println("hello, logfile")
  12. // attempt #2
  13. log.SetOutput(io.Writer(f))
  14. log.Println("hello, logfile")
  15. // attempt #3
  16. log.SetOutput(f)
  17. log.Println("hello, logfile")
  18. }
  19. func FileExists(name string) bool {
  20. if _, err := os.Stat(name); err != nil {
  21. if os.IsNotExist(err) {
  22. return false
  23. }
  24. }
  25. return true
  26. }
  27. func CreateFile(name string) error {
  28. fo, err := os.Create(name)
  29. if err != nil {
  30. return err
  31. }
  32. defer func() {
  33. fo.Close()
  34. }()
  35. return nil
  36. }

The log file gets created, but nothing ever gets printed or appended to it. Why?

答案1

得分: 215

os.Open()在过去的工作方式可能有所不同,但对我来说这样可以工作:

  1. f, err := os.OpenFile("testlogfile", os.O_RDWR | os.O_CREATE | os.O_APPEND, 0666)
  2. if err != nil {
  3. log.Fatalf("error opening file: %v", err)
  4. }
  5. defer f.Close()
  6. log.SetOutput(f)
  7. 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:

  1. f, err := os.OpenFile("testlogfile", os.O_RDWR | os.O_CREATE | os.O_APPEND, 0666)
  2. if err != nil {
  3. log.Fatalf("error opening file: %v", err)
  4. }
  5. defer f.Close()
  6. log.SetOutput(f)
  7. 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)。

  1. ./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).

  1. ./app 2>> logfile

See also: http://12factor.net/logs

答案3

得分: 42

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

  1. f, err := os.OpenFile("/tmp/orders.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
  2. if err != nil {
  3. log.Fatalf("打开文件时出错:%v", err)
  4. }
  5. defer f.Close()
  6. wrt := io.MultiWriter(os.Stdout, f)
  7. log.SetOutput(wrt)
  8. log.Println("调用了订单 API")
英文:

I usually print the logs on screen and write into a file as well. Hope this helps someone.

  1. f, err := os.OpenFile("/tmp/orders.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
  2. if err != nil {
  3. log.Fatalf("error opening file: %v", err)
  4. }
  5. defer f.Close()
  6. wrt := io.MultiWriter(os.Stdout, f)
  7. log.SetOutput(wrt)
  8. log.Println(" Orders API Called")

答案4

得分: 12

这对我来说没问题。

  1. 创建一个名为logger.go的包
  1. package logger
  2. import (
  3. "flag"
  4. "os"
  5. "log"
  6. "go/build"
  7. )
  8. var (
  9. Log *log.Logger
  10. )
  11. func init() {
  12. // 设置日志文件的位置
  13. var logpath = build.Default.GOPATH + "/src/chat/logger/info.log"
  14. flag.Parse()
  15. var file, err1 = os.Create(logpath)
  16. if err1 != nil {
  17. panic(err1)
  18. }
  19. Log = log.New(file, "", log.LstdFlags|log.Lshortfile)
  20. Log.Println("LogFile : " + logpath)
  21. }
  1. 在需要记录日志的地方导入该包,例如main.go
  1. package main
  2. import (
  3. "logger"
  4. )
  5. const (
  6. VERSION = "0.13"
  7. )
  8. func main() {
  9. // 使用我们的日志记录器,打印版本、进程ID和正在运行的进程数
  10. logger.Log.Printf("Server v%s pid=%d started with processes: %d", VERSION, os.Getpid(), runtime.GOMAXPROCS(runtime.NumCPU()))
  11. }
英文:

This works for me

  1. created a package called logger.go

    1. package logger
    2. import (
    3. "flag"
    4. "os"
    5. "log"
    6. "go/build"
    7. )
    8. var (
    9. Log *log.Logger
    10. )
    11. func init() {
    12. // set location of log file
    13. var logpath = build.Default.GOPATH + "/src/chat/logger/info.log"
    14. flag.Parse()
    15. var file, err1 = os.Create(logpath)
    16. if err1 != nil {
    17. panic(err1)
    18. }
    19. Log = log.New(file, "", log.LstdFlags|log.Lshortfile)
    20. Log.Println("LogFile : " + logpath)
    21. }
  2. import the package wherever you want to log e.g main.go

    1. package main
    2. import (
    3. "logger"
    4. )
    5. const (
    6. VERSION = "0.13"
    7. )
    8. func main() {
    9. // time to use our logger, print version, processID and number of running process
    10. logger.Log.Printf("Server v%s pid=%d started with processes: %d", VERSION, os.Getpid(),runtime.GOMAXPROCS(runtime.NumCPU()))
    11. }

答案5

得分: 10

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

覆盖写入文件:

  1. ./binaryapp > binaryapp.log

追加写入文件:

  1. ./binaryapp >> binaryapp.log

覆盖写入标准错误到文件:

  1. ./binaryapp &> binaryapp.error.log

追加写入标准错误到文件:

  1. ./binaryapp &>> binaryapp.error.log

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

英文:

If you run binary on linux machine you could use shell script.

overwrite into a file

  1. ./binaryapp > binaryapp.log

append into a file

  1. ./binaryapp >> binaryapp.log

overwrite stderr into a file

  1. ./binaryapp &> binaryapp.error.log

append stderr into a file

  1. ./binaryapp &>> binalyapp.error.log

it can be more dynamic using shell script file.

答案6

得分: 6

在全局var中声明,以便所有进程都可以访问(如果需要)。

  1. package main
  2. import (
  3. "log"
  4. "os"
  5. )
  6. var (
  7. outfile, _ = os.Create("path/to/my.log") // 根据你的需求更新路径
  8. l = log.New(outfile, "", 0)
  9. )
  10. func main() {
  11. l.Println("hello, log!!!")
  12. }
英文:

Declare up top in your global var so all your processes can access if needed.

  1. package main
  2. import (
  3. "log"
  4. "os"
  5. )
  6. var (
  7. outfile, _ = os.Create("path/to/my.log") // update path for your needs
  8. l = log.New(outfile, "", 0)
  9. )
  10. func main() {
  11. l.Println("hello, log!!!")
  12. }

答案7

得分: 5

Go语言中的默认日志记录器将日志写入stderr(2)。
将日志重定向到文件。

  1. import (
  2. "syscall"
  3. "os"
  4. )
  5. func main() {
  6. fErr, err := os.OpenFile("Errfile", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
  7. syscall.Dup2(int(fErr.Fd()), 1) /* -- stdout */
  8. syscall.Dup2(int(fErr.Fd()), 2) /* -- stderr */
  9. }
英文:

The default logger in Go writes to stderr (2).
redirect to file

  1. import (
  2. "syscall"
  3. "os"
  4. )
  5. func main(){
  6. fErr, err = os.OpenFile("Errfile", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
  7. syscall.Dup2(int(fErr.Fd()), 1) /* -- stdout */
  8. syscall.Dup2(int(fErr.Fd()), 2) /* -- stderr */
  9. }

答案8

得分: 5

根据Allison和Deepak的回答,我开始使用logrus,并且非常喜欢它:

  1. var log = logrus.New()
  2. func init() {
  3. // 同时输出到控制台和文件
  4. f, err := os.OpenFile("crawler.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
  5. if err != nil {
  6. log.Fatalf("打开文件时发生错误: %v", err)
  7. }
  8. wrt := io.MultiWriter(os.Stdout, f)
  9. log.SetOutput(wrt)
  10. }
  11. 在主函数中我有一个 `defer f.Close()`
英文:

Building on Allison and Deepak's answer, I started using logrus and really like it:

  1. var log = logrus.New()
  2. func init() {
  3. // log to console and file
  4. f, err := os.OpenFile("crawler.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
  5. if err != nil {
  6. log.Fatalf("error opening file: %v", err)
  7. }
  8. wrt := io.MultiWriter(os.Stdout, f)
  9. log.SetOutput(wrt)
  10. }

I have a defer f.Close() in the main function

答案9

得分: 0

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

  1. var (
  2. serverLogger *log.Logger
  3. )
  4. func init() {
  5. // 设置日志文件的位置
  6. date := time.Now().Format("2006-01-02")
  7. var logpath = os.Getenv(constant.XDirectoryPath) + constant.LogFilePath + date + constant.LogFileExtension
  8. os.MkdirAll(os.Getenv(constant.XDirectoryPath)+constant.LogFilePath, os.ModePerm)
  9. flag.Parse()
  10. var file, err1 = os.OpenFile(logpath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
  11. if err1 != nil {
  12. panic(err1)
  13. }
  14. mw := io.MultiWriter(os.Stdout, file)
  15. serverLogger = log.New(mw, constant.Empty, log.LstdFlags)
  16. serverLogger.Println("LogFile : " + logpath)
  17. }
  18. // LogServer 将日志记录到服务器的日志文件中
  19. func LogServer(logLevel enum.LogLevel, message string) {
  20. _, file, no, ok := runtime.Caller(1)
  21. logLineData := "logger_server.go"
  22. if ok {
  23. file = shortenFilePath(file)
  24. logLineData = fmt.Sprintf(file + constant.ColonWithSpace + strconv.Itoa(no) + constant.HyphenWithSpace)
  25. }
  26. serverLogger.Println(logLineData + logLevel.String() + constant.HyphenWithSpace + message)
  27. }
  28. // ShortenFilePath 将文件路径缩短为 a/b/c/d.go 到 d.go
  29. func shortenFilePath(file string) string {
  30. short := file
  31. for i := len(file) - 1; i > 0; i-- {
  32. if file[i] == constant.ForwardSlash {
  33. short = file[i+1:]
  34. break
  35. }
  36. }
  37. file = short
  38. return file
  39. }

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

  1. var (
  2. serverLogger *log.Logger
  3. )
  4. func init() {
  5. // set location of log file
  6. date := time.Now().Format("2006-01-02")
  7. var logpath = os.Getenv(constant.XDirectoryPath) + constant.LogFilePath + date + constant.LogFileExtension
  8. os.MkdirAll(os.Getenv(constant.XDirectoryPath)+constant.LogFilePath, os.ModePerm)
  9. flag.Parse()
  10. var file, err1 = os.OpenFile(logpath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
  11. if err1 != nil {
  12. panic(err1)
  13. }
  14. mw := io.MultiWriter(os.Stdout, file)
  15. serverLogger = log.New(mw, constant.Empty, log.LstdFlags)
  16. serverLogger.Println("LogFile : " + logpath)
  17. }
  18. // LogServer logs to server's log file
  19. func LogServer(logLevel enum.LogLevel, message string) {
  20. _, file, no, ok := runtime.Caller(1)
  21. logLineData := "logger_server.go"
  22. if ok {
  23. file = shortenFilePath(file)
  24. logLineData = fmt.Sprintf(file + constant.ColonWithSpace + strconv.Itoa(no) + constant.HyphenWithSpace)
  25. }
  26. serverLogger.Println(logLineData + logLevel.String() + constant.HyphenWithSpace + message)
  27. }
  28. // ShortenFilePath Shortens file path to a/b/c/d.go tp d.go
  29. func shortenFilePath(file string) string {
  30. short := file
  31. for i := len(file) - 1; i > 0; i-- {
  32. if file[i] == constant.ForwardSlash {
  33. short = file[i+1:]
  34. break
  35. }
  36. }
  37. file = short
  38. return file
  39. }

"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)打开,都可以直接进行开关切换,以便选择输出方式。

  1. func myLog(msg ...interface{}) {
  2. defer func() { r := recover(); if r != nil { fmt.Print("检测到错误日志:", r) } }()
  3. if conf.DEBUG {
  4. fmt.Println(msg)
  5. } else {
  6. logfile, err := os.OpenFile(conf.LOGDIR+"/"+conf.AppName+".log", os.O_RDWR | os.O_CREATE | os.O_APPEND,0666)
  7. if !checkErr(err) {
  8. log.SetOutput(logfile)
  9. log.Println(msg)
  10. }
  11. defer logfile.Close()
  12. }
  13. }

希望这能帮到你!

英文:

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.

  1. func myLog(msg ...interface{}) {
  2. defer func() { r := recover(); if r != nil { fmt.Print("Error detected logging:", r) } }()
  3. if conf.DEBUG {
  4. fmt.Println(msg)
  5. } else {
  6. logfile, err := os.OpenFile(conf.LOGDIR+"/"+conf.AppName+".log", os.O_RDWR | os.O_CREATE | os.O_APPEND,0666)
  7. if !checkErr(err) {
  8. log.SetOutput(logfile)
  9. log.Println(msg)
  10. }
  11. defer logfile.Close()
  12. }
  13. }
  14. </details>
  15. # 答案11
  16. **得分**: 0
  17. 也许这会对你有所帮助(如果日志文件存在,则使用它,如果不存在则创建):
  18. ```go
  19. package main
  20. import (
  21. "flag"
  22. "log"
  23. "os"
  24. )
  25. // 声明Log变量,用于记录事件。
  26. var (
  27. Log *log.Logger = Loggerx()
  28. )
  29. func Loggerx() *log.Logger {
  30. LOG_FILE_LOCATION := os.Getenv("LOG_FILE_LOCATION")
  31. // 如果环境变量存在,则使用Docker的配置。
  32. if LOG_FILE_LOCATION == "" {
  33. LOG_FILE_LOCATION = "../logs/" + APP_NAME + ".log"
  34. } else {
  35. LOG_FILE_LOCATION = LOG_FILE_LOCATION + APP_NAME + ".log"
  36. }
  37. flag.Parse()
  38. // 如果文件不存在,则创建一个新的日志文件。
  39. if _, err := os.Stat(LOG_FILE_LOCATION); os.IsNotExist(err) {
  40. file, err1 := os.Create(LOG_FILE_LOCATION)
  41. if err1 != nil {
  42. panic(err1)
  43. }
  44. // 如果文件不存在,则创建一个新的日志文件。
  45. return log.New(file, "", log.Ldate|log.Ltime|log.Lshortfile)
  46. } else {
  47. // 如果文件存在,则重用它。
  48. file, err := os.OpenFile(LOG_FILE_LOCATION, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0666)
  49. if err != nil {
  50. panic(err)
  51. }
  52. return log.New(file, "", log.Ldate|log.Ltime|log.Lshortfile)
  53. }
  54. }

更多详细信息请参阅:https://su9.co/9BAE74B

英文:

maybe this will help you (if the log file exists use it, if it does not exist create it):

  1. package main
  2. import (
  3. &quot;flag&quot;
  4. &quot;log&quot;
  5. &quot;os&quot;
  6. )
  7. //Se declara la variable Log. Esta ser&#225; usada para registrar los eventos.
  8. var (
  9. Log *log.Logger = Loggerx()
  10. )
  11. func Loggerx() *log.Logger {
  12. LOG_FILE_LOCATION := os.Getenv(&quot;LOG_FILE_LOCATION&quot;)
  13. //En el caso que la variable de entorno exista, el sistema usa la configuraci&#243;n del docker.
  14. if LOG_FILE_LOCATION == &quot;&quot; {
  15. LOG_FILE_LOCATION = &quot;../logs/&quot; + APP_NAME + &quot;.log&quot;
  16. } else {
  17. LOG_FILE_LOCATION = LOG_FILE_LOCATION + APP_NAME + &quot;.log&quot;
  18. }
  19. flag.Parse()
  20. //Si el archivo existe se rehusa, es decir, no elimina el archivo log y crea uno nuevo.
  21. if _, err := os.Stat(LOG_FILE_LOCATION); os.IsNotExist(err) {
  22. file, err1 := os.Create(LOG_FILE_LOCATION)
  23. if err1 != nil {
  24. panic(err1)
  25. }
  26. //si no existe,se crea uno nuevo.
  27. return log.New(file, &quot;&quot;, log.Ldate|log.Ltime|log.Lshortfile)
  28. } else {
  29. //si existe se rehusa.
  30. file, err := os.OpenFile(LOG_FILE_LOCATION, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0666)
  31. if err != nil {
  32. panic(err)
  33. }
  34. return log.New(file, &quot;&quot;, log.Ldate|log.Ltime|log.Lshortfile)
  35. }
  36. }

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:

确定