Should I close log file in Go?

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

Should I close log file in Go?

问题

我在utils包的init()方法中创建了一个全局的Logger。

package utils

import (
	"log"
	"os"
	"path/filepath"

	"github.com/some/package/config"
)

var Logger *log.Logger

func init() {
	logFile, _ := config.Configure.String("log_file")
	if len(logFile) == 0 {
		appRoot, _ := os.Getwd()
		logFile = filepath.Join(appRoot, "app_runtime.log")
	}

	f, err := os.OpenFile(logFile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
	if err != nil {
		panic(err)
	}
	Logger = log.New(f, "", log.LstdFlags)

	// Only log the debug severity or above.
	Logger.SetLevel(log.DebugLevel)
}

因此,你可以像这样使用它:

utils.Logger.Info("This is debug info")

关于你的问题:我应该关闭日志文件吗?如何关闭?

在你的代码中,你没有关闭日志文件。在程序结束时,操作系统会自动关闭文件描述符,所以你不需要手动关闭它。但是,如果你想在程序运行期间显式地关闭日志文件,你可以调用f.Close()方法来关闭文件。例如:

f.Close()

请注意,如果你在程序的其他地方继续使用Logger,关闭日志文件可能会导致错误。因此,在关闭日志文件之前,请确保你不再需要使用Logger

英文:

I created a Global Logger in a utils package's init() method.


     package utils

     var Logger *log.Logger

     func init() {

	  logFile, _ := config.Configure.String("log_file")
	  if len(logFile) == 0 {
		 appRoot, _ := os.Getwd()
		 logFile = filepath.Join(appRoot, "app_runtime.log")
	  }

	  f, err := os.OpenFile(logFile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
      //Look HERE!!! 

	  if err != nil {
		 panic(err)
	  }
	  Logger = log.New()

	  //Log as JSON
	  Logger.Formatter = &log.JSONFormatter{}

	  //Output to stdout
	  //When production, use file
	  Logger.Out = f

	  // Only log the debug severity or above.
	  Logger.Level = log.DebugLevel
    }


So, I can use it like this:

utils.Logger.Info("This is debug info")

My question is: Should I close the log file? How?

答案1

得分: 5

默认情况下,os.File 在应用程序退出时会由垃圾回收器(GC)进行最终化处理。根据SetFinalizer的文档:

> 对象 obj 的终结器会在 obj 变得不可达后的某个任意时间点被调度运行。不能保证终结器会在程序退出之前运行,因此通常它们只在长时间运行的程序中用于释放与对象关联的非内存资源。例如,当程序丢弃一个未调用 Close 的 os.File 对象时,可以使用终结器来关闭关联的操作系统文件描述符,但是依赖终结器来刷新内存中的 I/O 缓冲区(如 bufio.Writer)是错误的,因为缓冲区在程序退出时不会被刷新。

如果你不想依赖垃圾回收器,可以在 main 函数中手动关闭它,代码如下:

func main() {
    // 在退出时关闭日志写入器
    defer func(){
        if file, ok := Logger.Out.(*os.File); ok {
            file.Sync()
            file.Close()
        } else if handler, ok := Logger.Out.(io.Closer); ok {
            handler.Close()
        }
    }()
    
    // 你的原始代码
    //...
}

在上面的代码中,我们使用 defer 语句确保在应用程序退出时关闭 handler。由于 Logger.Out 可能被定义为 io.Writer,我们需要测试 Logger.Out 是否也实现了 io.Closer 接口,如果是,则关闭它。如果 Logger.Out 是一个 os.File,我们还调用 Sync() 来确保所有内容都被写入磁盘。

编辑
引用文档并添加 file.Sync() 来确保文件内容被写入磁盘。

英文:

By default, os.File will be finalized by the Garbage Collector (GC) when application exit. From SetFinalizer documentation

> The finalizer for obj is scheduled to run at some arbitrary time after obj becomes unreachable. There is no guarantee that finalizers will run before a program exits, so typically they are useful only for releasing non-memory resources associated with an object during a long-running program. For example, an os.File object could use a finalizer to close the associated operating system file descriptor when a program discards an os.File without calling Close, but it would be a mistake to depend on a finalizer to flush an in-memory I/O buffer such as a bufio.Writer, because the buffer would not be flushed at program exit.

If you don't want to rely on GC, you can close it manually in the main function as follows:

func main() {
    //Close log writer when exit
    defer func(){
        if file, ok := Logger.Out.(*os.File); ok {
            file.Sync()
            file.Close()
        } else if handler, ok := Logger.Out.(io.Closer); ok {
            handler.Close()
        }
    }()
    
    //Your original codes
    //...
}

In the above code, we use defer statement to ensure the handler will be closed when the application exit. Since Logger.Out may be defined as io.Writer, we need to test whether the Logger.Out also implements io.Closer, and if yes, it will be closed. If Logger.Out is an os.File, we also call Sync() to ensure all the content is written to disk.

EDIT
Quote documentation and add file.Sync() to ensure file content is written to disk.

huangapple
  • 本文由 发表于 2017年6月21日 13:46:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/44667733.html
匿名

发表评论

匿名网友

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

确定