首页 bad file descriptor
文章
取消

bad file descriptor

web 后端程序启动时,日志打印部分出错:

1
zerolog: could not write event: write logs/broker.log: bad file descriptor

原因在于 zerologger.Logger 创建时使用的 file 对象,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
func GetLogger(logDir, logName string) *zerolog.Logger {
	zerolog.TimeFieldFormat = zerolog.TimeFormatUnixMs
	zerolog.ErrorStackMarshaler = pkgerrors.MarshalStack
	zerolog.TimestampFieldName = "t"
	zerolog.LevelFieldName = "l"

	// 创建目录
	logDir = strings.ReplaceAll(logDir, " ", "")
	logDir = strings.TrimRight(logDir, "/")
	if logDir == "" {
		log.Fatal("log dir is invalid")
	}
	if _, err := os.Stat(logDir); os.IsNotExist(err) {
		// create log dir
		err = os.MkdirAll(logDir, 0o666)
		if err != nil {
			log.Fatal(err)
		}
	}

	logName = strings.ReplaceAll(logName, " ", "")
	if logName == "" {
		logName = "broker.log"
	} else if !strings.HasSuffix(logName, ".log") {
		logName = logName + ".log"
	}

	logPath := fmt.Sprintf("%s/%s", logDir, logName)
	//var err error
	var file *os.File
	if _, err := os.Stat(logPath); os.IsNotExist(err) {
		// create log file
		file, err = os.Create(logPath)
		if err != nil {
			log.Fatal(err)
		}
	} else {
		// open log file
		file, err = os.Open(logPath)
		if err != nil {
			log.Fatal(err)
		}
	}
	logger := zerolog.New(file)
	return &logger
}

在日志文件不存在时,file 是由 os.Open() 得来,但 os.Open 实际上实现如下:

1
2
3
4
5
6
7
// Open opens the named file for reading. If successful, methods on
// the returned file can be used for reading; the associated file
// descriptor has mode O_RDONLY.
// If there is an error, it will be of type *PathError.
func Open(name string) (*File, error) {
	return OpenFile(name, O_RDONLY, 0)
}

可以看到,返回的 file 只读,拿去写就会有问题。

再来说下文件描述符(file descriptor),文件描述符是一个标识计算机操作系统中打开的文件(广义上的文件,下同)的唯一非负整数。它描述了一个数据源,以及数据源怎样被访问。

每个被打开的文件都至少有一个文件描述符,可以同时有多个文件描述符。

当一个进程成功打开一个文件描述符,操作系统内核返回一个文件描述符,该文件描述符指向一个全局文件表的项。文件表向包含被打开文件的 inode、字节偏移量,以及数据流的访问限制(只读、只写,等等)。

文件描述符.png

言归正传,解决方法就是把文件打开方式修改一下:

file, err = os.Open(logPath) 修改为 file, err = os.OpenFile(logPath, os.O_RDWR, 0) 即可。

本文由作者按照 CC BY 4.0 进行授权