rm -rf 删掉日志文件后,为什么重启服务能恢复?
1.问题背景
把所有服务的“临界点”以上的错误都保存在/var/log/alert.log ⽇志中
1.打开系统⽇志的配置⽂件
vi /etc/rsyslog.conf
2.在规则模块中, 配置需求要求的内容
# ALL SERVICE CRIT TO /var/log/alert.log
*.crit action(type="omfile" file="/var/log/alert.log")
# 这个需要在本某块上面,规则模块下面
顺便给服务打开

3.进行测试
1.测试优先级大于这个的
logger -p alert "12324 249nc90ju90nj-0
看测试结果


2.测试优先级小于这个的
logger -p info "12324 249nc90ju90nj-0

2.出现问题
当时我把日志文件alert.log给删掉了,想要从空日志从优先级小的开始测试,再测试优先级高的,结果就出现问题了,怎么也无法找到这个日志文件,即使后面手动创建日志文件也是不可以的,因此呢,我当时就比较着急,因为佳乐老师并没有出现这种问题,我却出现了,不知道是我的配置文件出错了,还是怎么回事,我看了一番发现其实我写的 并没有任何问题,只不过后面我问ai,知道了原因
1.删除日志文件
rm -rf /var/log/alert.log #我用来清空日志文件,以便再次测试
2.出现问题
- 问题1:是我无法找到这个日志文件,我听佳乐老师说使用logger这个命令是可以自动创建文件以及文件夹的,但是我的这个所展示的情况与佳乐老师所描述的有些不同

- 问题2:是我手动创建了这个日志文件,但是启动这个logger服务是依然无法写入日志内容的
理论上说,优先级大于或者等于crit的才会在alarm.log日志里面写入日志的,但是目前所展示的情况好像和我想得不一样,即使与它的优先级一样,但是依然是无法写入文件的,这又是一点
3.问题原因
1.后来,我检查了我的配置文件,以及输入的命令,是没有任何错误的,然后我问了一下元宝,他给了我解决的方法,我开始问他为何无法自动创建日志文件呢,他说
1.配置规则的触发机制:在 Linux 的 rsyslog 配置中,文件输出通常是“按需创建”的。这意味着,只有当符合条件的日志真正产生并被写入时,对应的文件才会被创建。
2.日志级别不匹配导致“静默丢弃”:在配置文件中,有一条规则是 *.info;mail.none;authpriv.none;cron.none action(...)。这条规则的意思是:将所有设施的 info 级别及以上的日志写入某个文件(被截断了,通常是 /var/log/messages),但同时显式排除了 authpriv(认证授权)和 cron(定时任务)的日志。
3.命令的级别不够高:执行的命令是 logger -p crit "..."。虽然这里指定了级别为 crit(严重),但由于它默认使用的是 user 设施(即 user.crit),它没有被上述那条规则排除,因此被正确地路由到了 info 以上的通用日志规则中。
4.结果:日志被写入了那个通用的大文件里,根本没有走到下面 *.crit action(type="omfile" file="/var/log/alert.log") 这条规则。因此,/var/log/alert.log 这个文件从未被触发创建,自然就找不到了。
2.我看了一眼他说的,我认为是无法正常创建文件导致的,我手动创建了一个,结果依然是不行的,后面我又问了一下他为何我创建的文件还是没有内容呢,他说是 SELinux 可能开启,让我检查一番,我看了,我的这个并没有开放
3.我问了一下,他,我的这个selinux并没有开放,他说可能是因为配置文件有语法冲突,rsyslog 内部报错,/var/log 目录的权限问题,服务没有重启,查看 rsyslog 丢弃日志的统计
这几点中我可以看明白的就只有前4个,但是前3个我之前都检查过了,没有任何问题,我明白可能我的服务没有重启,我就重启了这个服务,然后直接和预料的结果一样,显然成功了
4.解决问题
1.重启服务
systemctl restart rsyslog

2.测试
我们先在日志文件里面输入一些内容
优先级高的
优先级小的

发现和预想的结果一样,证明这个是可以的,我们的问题解决了,这个小作业也完成了
5.总结
我自己总结
之所以是删除了日志文件然后再用logger输入相关指令不能写入文件其实是由于,当 rsyslog 服务启动时,它会读取配置文件,发现需要往 /var/log/alert.log 写日志。于是它向内核申请一个文件描述符(FD),就像拿到了一个直通文件的“管道”,然后日志文件删掉之后,FD还存在,但是之前的日志文件没有了,写入数据顺着之前日志文件的FD写入磁盘,只不过因为删了日志文件,无法成功查找到他,但是如果重启这个服务,会释放掉旧的FD,然后会申请一个新的FD,这样写入数据是根据这个新的FD来的,不是按照删除的FD来的,所以这个时候是可以写入的 照我看来,其实这个就有些像指针与地址的关系,当我们写入数据要解引用这个指针,方可写入,但是如果我们把这个变量给赋值给其他变量,还是对这个新变量赋值,但是由于指针指向的地址其实就是之前的变量地址,赋值也是把值送给之气的地址,因此新的变量还是之前的旧的数据。C语言里的全局变量的作用范围其实是全局,但是局部变量因为地址就在本地生效,即使在其他地方定义了一个一样的名字,也很难生效,无法赋值.
我查阅资料总结
为什么删除了 /var/log/alert.log 后,logger 命令看似“写不进去”?其实数据通常仍然在被写入,只是我们看不到了。
严格来说,logger 本身一般不是直接写 /var/log/alert.log,而是把日志消息发送给 rsyslog 服务,真正负责写入文件的是 rsyslog。
当 rsyslog 启动时,它会读取配置文件,发现需要向 /var/log/alert.log 输出日志。于是它调用 open() 打开这个文件,并从内核获得一个文件描述符,也就是 FD。这个 FD 本质上是一个整数句柄,比如 3。可以把它理解成进程文件描述符表中的一个下标:内核根据这个下标找到对应的 struct file 对象,而 struct file 又通过 dentry 关联到 inode 和磁盘数据块。
当我们执行:
rm /var/log/alert.log
删除的只是目录项,也就是文件名到 inode 的映射关系。好比把门牌号摘掉了,但房子本身还在。更准确地说,删除的是一个路径入口,而不是立刻销毁文件对象。因为 rsyslog 仍然持有旧的 FD,所以内核中对应的 struct file 仍然有效,它指向的 inode 也仍然有效。
因此,之后 rsyslog 调用 write() 时,数据仍然会顺着旧的 FD 写入原来的 inode 和数据块。写入本身通常并没有失败,只是 /var/log/alert.log 这个路径已经不存在了,所以你无法再通过原路径 cat 到内容。这就是为什么用 lsof 能看到该文件处于 (deleted) 状态:文件对象还活着,只是没有名字了。
重启服务后为什么会恢复?
因为重启会让旧的 rsyslog 进程退出,旧的 FD 会被关闭,对应的 struct file 引用减少。当这个旧 inode 不再被任何打开句柄或硬链接引用时,磁盘空间才会真正释放。随后新的 rsyslog 进程启动,重新调用 open() 打开或创建 /var/log/alert.log,获得新的 FD,指向新的文件对象。从此以后,日志走的是新 FD,写的是新文件,所以就能看见了。
如果用 C 语言的指针来类比,可以这样理解:
路径名 /var/log/alert.log 类似于变量名
inode 类似于真正的对象
FD 类似于进程持有的指针/引用
rm 删除文件更像删除变量名、删除别名,或者解除一个目录项引用,而不是立刻释放底层对象。只要 rsyslog 还持有 FD 这个“指针”,它就可以继续通过这个指针写入原来的对象。重启服务则相当于让进程放弃旧指针,重新 open() 一个新对象,拿到新的指针。
不过,这里不能完全类比成 free(p) 后继续使用 p。在 C 语言里,free(p) 后再解引用 p 是悬垂指针,属于未定义行为;而 Linux 文件这里是引用计数机制:删除目录项只是减少 inode 的一个引用,只要还有进程持有打开的文件描述符,文件对象仍然合法存在。
同样,在 Shell 里重新创建一个同名的 /var/log/alert.log,也无法把旧的日志流“接回来”。因为新的文件名指向新的 inode,而 rsyslog 手里的旧 FD 仍然指向旧 inode。除非让 rsyslog 重新打开日志文件,例如重启服务,或者在支持的情况下 reload、发送 HUP 信号,它才会关闭旧 FD,并根据新的路径名打开新的文件对象。
评论