You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go程序被Task Manager/taskkill终止时如何写入停止日志?

在Go中处理Windows下任务管理器/taskkill终止时的日志写入问题

问题根源

在Windows环境中,不同终止方式触发的系统信号/事件存在差异:

  • VS Code终端按CTRL+C发送的是SIGINT信号,Go标准库os/signal可直接捕获。
  • taskkill命令默认(不加/f参数)发送SIGTERM信号,但若加/f则是强制终止(调用TerminateProcess),这种情况无法捕获。
  • 任务管理器的"结束任务"操作,针对控制台程序通常触发控制台关闭事件,而非标准POSIX信号,os/signal包无法直接处理。

解决方案

1. 同时监听SIGINT和SIGTERM信号

覆盖CTRL+C和非强制taskkill场景:

package main

import (
    "log"
    "os"
    "os/signal"
    "syscall"
)

func main() {
    logFile, err := os.OpenFile("app.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
    if err != nil {
        log.Fatal(err)
    }
    defer logFile.Close()
    log.SetOutput(logFile)

    sigChan := make(chan os.Signal, 1)
    signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)

    <-sigChan

    log.Println("stopping")
    logFile.Sync() // 强制刷入磁盘,避免日志丢失
}

2. 处理Windows控制台关闭事件

针对任务管理器"结束任务"或关闭控制台窗口的场景,需调用Windows API捕获CTRL_CLOSE_EVENT事件,使用golang.org/x/sys/windows包实现:
先安装依赖:

go get golang.org/x/sys/windows

代码实现:

package main

import (
    "log"
    "os"
    "syscall"
    "golang.org/x/sys/windows"
)

var (
    kernel32             = windows.NewLazySystemDLL("kernel32.dll")
    setConsoleCtrlHandler = kernel32.NewProc("SetConsoleCtrlHandler")
)

func setConsoleHandler(handler func(uint32) bool) error {
    h, err := syscall.NewCallback(handler)
    if err != nil {
        return err
    }
    _, _, err = setConsoleCtrlHandler.Call(h, 1)
    if err != syscall.Errno(0) {
        return err
    }
    return nil
}

func main() {
    logFile, err := os.OpenFile("app.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
    if err != nil {
        log.Fatal(err)
    }
    defer logFile.Close()
    log.SetOutput(logFile)

    err = setConsoleHandler(func(dwCtrlType uint32) bool {
        switch dwCtrlType {
        case windows.CTRL_C_EVENT, windows.CTRL_CLOSE_EVENT, windows.CTRL_BREAK_EVENT, windows.CTRL_SHUTDOWN_EVENT:
            log.Println("stopping")
            logFile.Sync()
            return true // 标记事件已处理,系统不再执行默认终止逻辑
        }
        return false
    })
    if err != nil {
        log.Fatal(err)
    }

    select {} // 保持程序运行,模拟业务阻塞逻辑
}

3. 强制终止场景的局限性

若用户使用taskkill /f或任务管理器"结束进程"操作,系统会直接终止进程,此时任何代码都无法执行,无法写入日志。只能通过提示用户避免使用强制终止方式来规避。

关键注意点

  • 日志写入后必须调用File.Sync(),确保缓冲区内容刷入磁盘,防止进程终止导致日志丢失。
  • 若为Windows GUI程序,还需额外处理WM_CLOSE等窗口消息,控制台程序重点关注控制台关闭事件即可。

内容的提问来源于stack exchange,提问作者martinotecco

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 02:22:34