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