我有一个用 Go 编写并作为 Windows 服务运行的简单 TCP 服务器。它安装/卸载很好,它作为服务工作并完成它的工作,但它不会在日志文件中写一个字。当我在控制台中将它简单地作为可执行文件运行时 - 日志记录工作正常。但是当它作为服务启动时 - 创建了日志文件,应用程序进程打开它(例如不允许删除它)但文件仍然是空的。我做错了什么?
任何建议都表示赞赏。
logging 是这样定义的
func (p *Program) run() {
exec, _ := os.Executable()
WORK_DIR = filepath.Join(filepath.Dir(exec), "ATT")
_, err := checkDir(WORK_DIR)
if err != nil {
panic("Не удалось создать рабочий каталог")
}
f, err := os.OpenFile(filepath.Join(filepath.Dir(exec), "server.log"), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
log.Fatalf("Не удалось создать лог-файл: %v", err)
}
defer f.Close()
wrt := io.MultiWriter(os.Stdout, f)
log.SetOutput(wrt)
server, err := net.Listen("tcp", ":"+PORT)
if err != nil {
log.Fatal(err)
}
defer server.Close()
log.Println("Сервер запущен на порту:", PORT)
for {
connection, err := server.Accept()
if err != nil {
log.Println("Не удалось установить соединение с клиентом", err)
}
go HandleServer(connection)
}
}
您遇到的日志记录问题可能与作为服务运行时的文件权限有关。当服务启动时,它以不同于作为常规可执行文件运行时的一组权限运行。在某些情况下,该服务可能没有权限写入与可执行文件位于同一位置的日志文件。
一个可能的解决方案是为日志文件指定不同的位置,例如
C:\Windows\System32\LogFiles
,这是Windows中日志文件的常用位置。您还可以尝试在 OpenFile
调用中指定日志文件的绝对路径,以避免对工作目录产生任何混淆。
另一个潜在的问题可能与关闭日志文件的延迟语句有关。当服务终止时,将执行任何延迟的语句,这可能会导致日志文件在所有日志消息被写入之前关闭。为避免这种情况,您可以删除 defer 语句并在服务停止时手动关闭日志文件。
向日志记录调用添加错误处理可能也是一个好主意,以确保即使日志文件不可用也能写入所有日志消息。这是一个例子:
func (p *Program) run() {
exec, _ := os.Executable()
WORK_DIR = filepath.Join(filepath.Dir(exec), "ATT")
_, err := checkDir(WORK_DIR)
if err != nil {
panic("Не удалось создать рабочий каталог")
}
// Specify the absolute path for the log file
logFilePath := filepath.Join(filepath.Dir(exec), "server.log")
f, err := os.OpenFile(logFilePath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
log.Fatalf("Не удалось создать лог-файл: %v", err)
}
// Remove the defer statement to close the log file manually later
// defer f.Close()
wrt := io.MultiWriter(os.Stdout, f)
log.SetOutput(wrt)
server, err := net.Listen("tcp", ":"+PORT)
if err != nil {
log.Fatal(err)
}
defer server.Close()
log.Println("Сервер запущен на порту:", PORT)
for {
connection, err := server.Accept()
if err != nil {
log.Println("Не удалось установить соединение с клиентом", err)
}
go HandleServer(connection)
}
// Manually close the log file when the service stops
f.Close()
}
// Add error handling to the logging calls
func logMessage(message string) {
_, logErr := log.Println(message)
if logErr != nil {
fmt.Printf("Error logging message: %v\n", logErr)
}
}
希望这些建议能帮助您解决登录服务的问题。请告诉我。
原因是
wrt := io.MultiWriter(os.Stdout, f)
.
下面是 multiWriter 的实现。如果按顺序写入失败,则不再进行写入。
func (t *multiWriter) Write(p []byte) (n int, err error) {
for _, w := range t.writers {
n, err = w.Write(p)
if err != nil {
return
}
if n != len(p) {
err = ErrShortWrite
return
}
}
return len(p), nil
}
在 Windows 服务中,stdout 不起作用。如果你看wrt.Write的错误,那就是
write /dev/stdout: The handle is invalid
.