oracle 12c+监听器日志不支持自动轮转,必须通过lsnrctl set log_status off→mv日志→log_status on三步闭环实现;logrotate直接套用会因文件句柄未释放导致丢日志或空间不释放。

Oracle 12c+ 不支持监听器日志自动轮转,官方未提供 logrotate 兼容机制或内置 rollover 参数;所谓“自动轮转”只能靠外部脚本 + 手动干预组合实现,且必须关闭 log_status 后再操作文件,否则会丢日志或触发写异常。
为什么 logrotate 直接套用会失败
监听器进程在运行时始终以追加模式(O_APPEND)打开 listener.log,即使 log_status 为 on。此时若用 logrotate 的默认 copytruncate 或 rename 操作:
-
copytruncate会截断原文件,但监听器内部文件偏移量(offset)未重置,后续写入可能覆盖开头、产生乱码或跳写 -
rename(如 mv listener.log listener.log.1)在 Linux 下虽不报错,但 inode 仍被监听器持有,磁盘空间不会释放,df显示已满而du看不到大文件 - Windows 下直接 rename 或 delete 会失败,监听器报
ORA-12541或拒绝新连接
可行的“类轮转”方案:三步闭环操作
本质是模拟轮转行为:停写 → 搬走旧日志 → 启写新日志。必须按顺序执行,缺一不可:
- 先执行
lsnrctl set log_status off:立即停止所有日志写入,已打开的句柄保持但不再追加 - 再执行
mv $ORACLE_HOME/network/log/listener.log $ORACLE_HOME/network/log/listener.log.$(date +\%Y\%m\%d\%H\%M):安全移动,释放 inode,保留可读历史 - 最后执行
lsnrctl set log_status on:监听器检测到listener.log不存在,自动创建全新空文件并开始写入
注意:log_status on 后不会继承旧文件权限,新文件权限由 umask 决定(通常为 -rw-r--r--);若需特定属主,可在 mv 后加 chown oracle:oinstall。
如何用 cron 实现准自动清理(非真正轮转)
把上面三步封装成脚本,配合 cron 定期触发,是最贴近“自动轮转”的实用做法:
- 脚本中必须校验监听器状态:
lsnrctl status | grep -q "not running"失败则退出,避免对宕机监听器误操作 - 建议使用绝对路径调用
lsnrctl,例如$ORACLE_HOME/bin/lsnrctl,防止 cron 环境无$PATH - 日志保留策略靠文件名时间戳 +
find清理,例如:find $ORACLE_HOME/network/log -name "listener.log.*" -mtime +7 -delete - 不要依赖
lsnrctl reload:它不重载日志开关,也无法触发新日志创建
为什么不能改 LOG_DIRECTORY_LISTENER 指向 /dev/null 来“绕过”
该配置仅控制日志写入路径,不改变写入行为本身。设为 /dev/null 后:
- 监听器仍会尝试 open/write,只是数据被丢弃;
lsnrctl status中仍显示日志路径,且log_status仍为on - 若某次写入因权限或设备忙失败,监听器可能卡住或降级为静默失败,排查困难
- 无法满足审计要求——你连“是否真没写”都难验证,更别说追溯连接事件
真正需要日志审计时,唯一可靠路径仍是关 log_status + 定期归档 + 人工检查;想省事又保审计,不如直接关掉日志并接受无连接记录的事实。











