我有一个变得很大的日志文件。我能从中得到的信息可以忽略不计。
我想将它链接到/dev/null
.然而,即使它被“删除”(见下面lsof的输出),它也会消耗我所有的硬盘空间。
我可以使用以下方法截断它:
: > "/proc/$pid/fd/$fd"
# for instance:
: > "/proc/2456/fd/2"
不幸的是,系统上的某些进程在硬盘已满时会暂停,必须手动重新启动(并且我想避免进程被暂停)。
有没有办法在文件变得太大时自动截断文件(例如,当它消耗超过 1G 时?)
lsof
输出:
program 2456 user 2w REG 8,5 441433300992 0 21365598 /home/user/file (deleted)
答案1
仅当不再引用文件时,文件的内容才会被删除。对文件的引用可以是目录条目或打开的文件句柄。当您删除某个进程(rm
此处为记录该文件的进程)仍然打开的文件(例如使用命令)时,该文件的内容将保留,直到该进程关闭该文件。
摆脱旧日志的最直接方法是
- 将文件移动到另一个名称,例如
mv foo.log foo.log.old
- 指示进程重新打开其日志文件。如果该进程无法做到这一点,请重新启动它。
- 删除现已关闭的旧日志文件 (
rm foo.log.old
)。
该程序对数旋转自动化此机制,并且可以配置旧日志的保留天数。它还可以压缩旧日志。
对于步骤 2,如果您无法重新启动程序并且无法重新打开其日志文件,您可以尝试使用调试器强制使其重新打开日志文件。但是,请注意,如果程序保留有关现在变得不一致的日志文件的信息,则可能会使程序崩溃。概念验证(请注意,很多事情可能会出错;如果有疑问,请不要这样做):
gdb -n $pid -batch -x /dev/stdin <<EOF
call close(2)
call open("/path/to/foo.log", 1)
EOF
如果您不关心任何日志,则释放一些磁盘空间的另一种粗略方法是截断文件。日志记录进程将继续在文件中的同一位置写入,但该文件将成为稀疏文件。如果从头开始读取文件,您将得到空字节,但这些空字节仅占用磁盘上的几 kB。
dd if=/dev/null of=/path/to/foo.log
答案2
重新启动program
以释放已删除的文件。进行调查logrotate
等以正确管理日志数据,或调整程序以发出更少的日志消息。
答案3
当您删除文件时,您实际上并没有“删除”它。你把它取消链接。最终结果是打开日志文件的程序仍然可以访问日志文件,直到关闭它(这对于日志文件来说很少见)。
现在,为了正确解决您的问题,您需要研究日志轮换和日志过滤。
日志轮转将允许您根据一组规则进行归档、压缩和删除。例如,所有早于一天的条目都会被压缩,所有超过 7 天的条目都会被删除。
日志过滤只是减少进入日志的“东西”的数量。有些程序在程序端实现过滤,其他程序在记录器端实现过滤。例如,如果您使用 syslogd,您可以告诉它过滤掉所有事情上的非关键消息(再次举例)。
要快速解决问题,请重新启动服务,查明它是否响应非常常见的信号 SIGUSR1 和 SIGHUP,然后发送该信号,或者重新启动计算机。
答案4
如果日志文件是通过输出到stderr
或来创建的stdout
,并且如果您可以控制创建日志文件的程序(我们称之为bar
)的启动方式,请以 启动它bar &>/dev/null
,这会将所有标准输出或错误消息重定向到 /开发/空。
或者,(我知道这确实是不好的做法,但至少它会起作用)设置一个每小时的 cron 作业来终止创建日志的程序,删除日志文件,然后启动程序备份,前提是该程序不是对系统运行至关重要。再次假设该程序的名称是bar
,则执行此操作的方法是echo "* 0 0 0 0 \"/bin/killall [offending program]; /bin/rm [offending log]; [command to run program];\" 1>[crontab location]"
。
请注意,方括号用于表示占位符,不应出现在输入的命令中。
再次,请注意,第二种解决方案确实是不好的做法,总的来说只是绷带修复......所以使用它需要您自担风险。