守护进程启动后脱离终端,其 stdout 和 stderr 默认丢失,需显式重定向:systemd 服务可通过 standardoutput/standarderror 配置日志路径并配合轮转;手动 fork 守护进程需用 dup2 替换 fd 或重定向 sys.stdout/sys.stderr;supervisord 等工具支持直接指定日志文件;所有场景均须注意权限、追加写入及日志轮转。

守护进程启动后脱离终端,其 stdout 和 stderr 默认会丢失。要持久化查看输出,必须在启动时显式重定向,而非依赖 shell 重定向符号(如 >log 2>&1)——因为守护进程通常由 init 系统(systemd、supervisord)或 fork + setsid 启动,shell 重定向对其无效。
使用 systemd 服务时重定向日志
systemd 原生支持标准流捕获,无需手动重定向到文件:
- 默认情况下,stdout/stderr 会被 journalctl 收集,执行
journalctl -u your-service.service即可查看 - 若需同时写入独立日志文件,可在 service 文件中配置:
StandardOutput=append:/var/log/your-app.stdout.logStandardError=append:/var/log/your-app.stderr.log - 注意:路径需确保运行用户有写权限;建议配合
Rotate=和MaxSize=(需 systemd v240+)或用 logrotate 管理日志轮转
手动 fork 守护进程时的重定向方法
在代码中调用 fork() + setsid() 后,需主动关闭并重用文件描述符 1 和 2:
- C/Go 等语言:打开日志文件,用
dup2(fd, STDOUT_FILENO)和dup2(fd, STDERR_FILENO)替换标准输出/错误 - Python 示例(启动前):
sys.stdout = open('/var/log/app.log', 'a')sys.stderr = sys.stdout
(注意:需确保后续 print / logging 输出经此重定向,且避免缓冲问题) - 更稳妥做法是用
os.dup2()直接替换 fd,绕过高级 I/O 缓冲层
通过 exec wrapper 工具简化重定向
对无法修改源码的二进制程序,可用工具封装并接管输出:
-
stdbuf -oL -eL your-program >>/var/log/out.log 2>&1—— 仅适用于前台启动,不适用于真正 daemonize 场景 - 推荐使用
start-stop-daemon(Debian/Ubuntu)或daemon(RHEL/CentOS)命令,它们支持--stdout/--stderr参数直接指定日志路径 - supervisord 配置示例:
stdout_logfile=/var/log/app.logstderr_logfile=/var/log/app.errstdout_logfile_maxbytes=10MB
日志权限与轮转注意事项
重定向目标不是“能写就行”,还需兼顾安全与可维护性:
- 日志文件属主应与守护进程运行用户一致(如
www-data),禁止 root 写日志(除非必要且受控) - 避免使用
>覆盖模式,始终用>>或 systemd 的append:,防止重启时日志清空 - 单文件长期累积易失控,务必配置轮转:systemd 日志用
SystemMaxUse=,外部日志用 logrotate,并 reload 对应服务











