我们可以将所有控制台日志定向到文件吗?

can we direct all console log to file?

当 运行 Web 应用在本地使用命令

go run MainPackageFile.go

我们可以映射记录器,例如用马提尼

m := martini.Classic()
m.Get("/m", func() string {
  return "Hello world!"
})
m.Map(log.New(f, "[martini]", log.LstdFlags))

但是,如果代码外部出现问题怎么办,例如 Go 无法下载包等...有没有办法获取这些 Go 运行时日志? 当 运行 本地错误将打印到控制台上。有没有办法在服务器 运行 时,我们可以将所有这些日志写入文本文件?

您可以使用此函数将标准错误重定向到文件。这将收到回溯。

// redirectStderr to the file passed in
func redirectStderr(f *os.File) {
err := syscall.Dup2(int(f.Fd()), int(os.Stderr.Fd()))
    if err != nil {
        log.Fatalf("Failed to redirect stderr to file: %v", err)
    }
}

它只适用于 linux/mac/unix。

下面是如何为 windows

做同样的事情
var (
    kernel32 = syscall.MustLoadDLL("kernel32.dll")
    procSetStdHandle = kernel32.MustFindProc("SetStdHandle")
)

func setStdHandle(stdhandle int32, handle syscall.Handle) error {
    r0, _, e1 := syscall.Syscall(procSetStdHandle.Addr(), 2, uintptr(stdhandle), uintptr(handle), 0)
    if r0 == 0 {
        if e1 != 0 {
            return error(e1)
        }
        return syscall.EINVAL
    }
    return nil
}

// redirectStderr to the file passed in
func redirectStderr(f *os.File) {
    err := setStdHandle(syscall.STD_ERROR_HANDLE, syscall.Handle(f.Fd()))
    if err != nil {
        log.Fatalf("Failed to redirect stderr to file: %v", err)
    }
}

Original code from minux

假设您的代码使用日志库到处报告错误,您可以更改默认记录器写入的文件,而不是定义您自己的日志对象并将其四处传递。这是通过日志库的 SetOutput() 函数完成的。

这样,下面的代码将只写入您的日志文件而不是标准错误:

// Call this when your program starts and pass it the file handle for your
// log file.
func SetupErrorLog(logFile io.Writer) {
    log.SetOutput(logFile)
}

...

func DoSomething() {
    ...
    if err != nil {
       // prints to your log file and exits
       log.Fatalln("A fatal error has occurred:", err)
   }
}

如果您没有统一使用日志库并且想要捕获所有输出(如恐慌),那么接受的答案就可以了。但是,我更喜欢一种更简单的方法,而不是在调用程序时使用像记录器这样的工具来使代码复杂化:

go run MainPackageFile.go 2>&1 | logger

这会将您程序的所有输出发送到系统日志,而不必弄乱您的代码。 logger 命令有许多选项来自定义日志记录行为,包括选择您自己的日志文件的能力。阅读 logger man page 了解更多信息。

logger 命令在 Unix 系统(包括 Mac)上可用。 Windows 解决方案可能略有不同。