Golang中Listener导致stdin输入和日志记录失效问题

Golang中Listener导致stdin输入和日志记录失效问题 如果我将第19行和第20行注释掉(即不启动监听器),那么日志记录和等待功能都能正常工作。但如果保留这些代码,一旦监听器启动,后续的日志记录就无法进行。"before listener starts"能够正确记录,但"after listener starts"则不会。同时,等待标准输入的功能也无法正常工作。出于测试目的,我希望能够记录各种消息并时不时等待输入。有人知道解决方法吗?

package main
import ("fmt"
"net/http"
"log"
"os"
"bufio")
var	mux = http.NewServeMux()
func index(w http.ResponseWriter, r *http.Request) {   }
func main() {
mux.HandleFunc("/", index)
logFile, err1 := os.OpenFile("logfile.txt", os.O_RDWR|os.O_CREATE, 0755)
if err1 != nil { fmt.Println("error opening log file")
return }
defer logFile.Close()
log.SetOutput(logFile)
fmt.Println("test log pgm")
log.Println("before listener starts")
err := http.ListenAndServe(":8080", mux)    // take this out, and logging works correctly
log.Fatal(err)                                                // and this
log.Println("after listener starts")
wait()
return
}
func wait()   {
fmt.Println("waiting...")
log.Println("waiting...")
reader := bufio.NewReader(os.Stdin)
input, _ := reader.ReadString('\n')
input=input+"dummy"
}

更多关于Golang中Listener导致stdin输入和日志记录失效问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html

4 回复

引用 buzzersdad:

err := http.ListenAndServe(":8080", mux)    // 移除此行,日志记录即可正常工作

http.ListenAndServe() 会阻塞执行,因此在它返回错误之前,后续代码都不会被执行。

更多关于Golang中Listener导致stdin输入和日志记录失效问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


我通常在请求到达处理程序时立即进行日志记录。

如果你确实想在其后记录日志,可以使用 go 协程,但请注意!

go http.ListenAndServe(…)
fmt.Println("after ListenAndServe")

这里实际的打印可能会在 go 协程获得调度器分配的时间之前发生…

是的,谢谢,但我需要为我的应用程序设置一个监听器。那么当我有活跃的监听器时,就不能进行日志记录了吗?也许有其他的日志记录方式。如果我只是使用 fmt 输出到标准输出,它存储的输出量是有限的,在达到限制后会用更新的内容覆盖较早的内容。从应用程序的许多不同部分写入文件似乎有些过度。

func main() {
    fmt.Println("hello world")
}

问题分析:

当调用 http.ListenAndServe() 时,该函数会阻塞并持续监听HTTP请求,这意味着它不会返回(除非发生错误),因此后续的代码(包括日志记录和等待输入)无法执行。log.Fatal() 会在 ListenAndServe 返回错误时记录并退出程序,但正常情况下 ListenAndServe 不会返回。

解决方案:

需要在单独的goroutine中启动HTTP服务器,这样主goroutine可以继续执行后续的日志记录和等待输入功能。

修改后的代码示例:

package main

import (
	"bufio"
	"fmt"
	"log"
	"net/http"
	"os"
)

var mux = http.NewServeMux()

func index(w http.ResponseWriter, r *http.Request) {}

func main() {
	mux.HandleFunc("/", index)
	
	logFile, err1 := os.OpenFile("logfile.txt", os.O_RDWR|os.O_CREATE, 0755)
	if err1 != nil {
		fmt.Println("error opening log file")
		return
	}
	defer logFile.Close()
	log.SetOutput(logFile)
	
	fmt.Println("test log pgm")
	log.Println("before listener starts")
	
	// 在goroutine中启动HTTP服务器
	go func() {
		err := http.ListenAndServe(":8080", mux)
		if err != nil {
			log.Fatal(err)
		}
	}()
	
	log.Println("after listener starts")
	wait()
}

func wait() {
	fmt.Println("waiting...")
	log.Println("waiting...")
	reader := bufio.NewReader(os.Stdin)
	input, _ := reader.ReadString('\n')
	input = input + "dummy"
	log.Printf("Received input: %s", input)
}

关键修改:

  1. http.ListenAndServe() 调用包装在goroutine中:go func() { ... }()
  2. 移除了原来的 log.Fatal(err) 行,改为在goroutine内部处理错误
  3. 这样主goroutine可以继续执行到 log.Println("after listener starts")wait() 函数

现在HTTP服务器会在后台运行,同时程序可以正常记录日志并等待用户输入。

回到顶部