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

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

can we direct all console log to file?

问题

在本地运行Web应用程序时,可以使用以下命令:

go run MainPackageFile.go

我们可以使用Martini将日志映射起来,例如:

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

然而,如果在代码之外出现问题,例如Go无法下载包等等,有没有办法获取Go运行时的日志呢?在本地运行时,错误信息将打印到控制台上。在服务器上运行时,有没有办法将所有这些日志写入文本文件中呢?

英文:

when running web app locally with command

go run MainPackageFile.go

and we can map logger e.g with martini

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

however what if there is something wrong outside the code, e.g Go not able to download package etc... is there a way to get those go runtime log?
when running locally errors will print out onto console. is there a way when running in server, we can have all those log write into text file?

答案1

得分: 2

假设你的代码在各处使用log库来报告错误,你可以更改默认日志记录器写入的文件,而不是定义自己的日志对象并传递它。这可以通过log库的SetOutput()函数来实现。

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

// 在程序启动时调用此函数,并传递你的日志文件的文件句柄。
func SetupErrorLog(logFile io.Writer) {
log.SetOutput(logFile)
}

...

func DoSomething() {
...
if err != nil {
// 将错误信息写入日志文件并退出
log.Fatalln("发生致命错误:", err)
}
}

如果你没有统一使用log库,并且想要捕获所有输出(如panic),那么接受的答案是有效的。然而,我更喜欢一种更简单的方法,而不是通过在调用程序时使用logger工具来复杂化你的代码:

go run MainPackageFile.go 2>&1 | logger

这将把你程序的所有输出发送到syslog,而无需修改你的代码。logger命令有许多选项可以自定义日志记录行为,包括选择自己的日志文件。阅读logger手册页面以获取更多信息。

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

英文:

Assuming your code uses the log library to report errors everywhere, you can change the file that the default logger writes to rather than defining your own log object and passing it around. This is done via the log library's <a href="http://golang.org/pkg/log/#SetOutput">SetOutput()</a> function.

This way the following code would just write into your log file instead standard error:

// 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(&quot;A fatal error has occurred:&quot;, err)
   }
}

If you are not using the log library uniformly and you want to capture all output (like panics), then the accepted answer works. However, I'd prefer a much simpler approach without complicating your code by using a tool like logger when you invoke your program:

go run MainPackageFile.go 2&gt;&amp;1 | logger

This will send all of your program's output to syslog without having to mess with your code. The logger command has many options to customize logging behavior, including the ability to choose your own log file. Read the <a href="http://man7.org/linux/man-pages/man1/logger.1.html">logger man page</a> for more information.

The logger command is available on Unix systems (including Mac). The Windows solution might be a little different.

答案2

得分: 1

你可以使用这个函数将标准错误重定向到一个文件中,这将接收到回溯信息。

// 将标准错误重定向到传入的文件
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
}

// 将标准错误重定向到传入的文件
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)
    }
}

原始代码来自minux

英文:

You can use this function to redirect standard error to a file. This will receive tracebacks.

// 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(&quot;Failed to redirect stderr to file: %v&quot;, err)
    }
}

It only works on linux/mac/unix.

Here is how to do the same thing for windows

var (
    kernel32 = syscall.MustLoadDLL(&quot;kernel32.dll&quot;)
    procSetStdHandle = kernel32.MustFindProc(&quot;SetStdHandle&quot;)
)

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(&quot;Failed to redirect stderr to file: %v&quot;, err)
    }
}

Original code from minux

huangapple
  • 本文由 发表于 2015年3月26日 03:03:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/29264337.html
匿名

发表评论

匿名网友

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

确定