Rails配置STDOUT日志后无法在kubectl与Datadog中显示
问题根因
- 直接使用
Logger.new(STDOUT)初始化日志存在两个核心问题,导致日志无法进入容器标准输出流:- 缓冲模式不匹配:Ruby标准IO默认使用块缓冲,攒够8KB数据才会把内容真正写入STDOUT文件描述符;而
system('echo testing logging')调用的系统命令默认是行缓冲,输出一行就立刻刷新流,所以能被正常采集。Rails.logger的日志如果没触发缓冲刷新,会一直留在进程内存里,kubelet和Datadog的采集器根本读不到。 - 配置被Rails覆盖:Rails 5及以上版本在配置加载完成后,会对logger实例做二次封装,如果手动初始化的Logger不支持TaggedLogging等内置接口,会被静默替换为默认的文件日志实例,日志实际写入了容器内的
log/<环境名>.log文件,根本没有输出到STDOUT。
- 缓冲模式不匹配:Ruby标准IO默认使用块缓冲,攒够8KB数据才会把内容真正写入STDOUT文件描述符;而
- 额外场景:如果使用Puma、Unicorn这类应用服务器,服务器自身默认也会做输出重定向或者缓冲,没做对应配置的话也会吞掉STDOUT日志。
快速排查方法
- 进入运行中的容器,查看应用日志目录下的文件:执行
cat log/production.log(生产环境),如果能看到Rails.logger.info输出的内容,就证明配置的STDOUT logger被框架覆盖了。 - 临时在初始化logger的配置下加一行
STDOUT.sync = true重启服务,如果日志能正常显示,就确定是缓冲未刷新导致的问题。
可落地解决方案
替换原有日志配置为兼容全Rails版本的标准配置,配置写到对应环境的配置文件(生产环境为config/environments/production.rb):
config.log_level = :info # 强制STDOUT开启行同步,每输出一行立刻刷流,禁用块缓冲 STDOUT.sync = true # 用Rails原生的ActiveSupport::Logger初始化,避免被框架替换 config.logger = ActiveSupport::Logger.new(STDOUT) .tap { |logger| logger.formatter = Logger::Formatter.new } .then { |logger| ActiveSupport::TaggedLogging.new(logger) } # 单条日志写入后立刻刷新,不攒批 config.logger.auto_flushing = 1 # 适配高版本Rails的内置开关,强制日志输出到STDOUT config.log_to_stdout = true if config.respond_to?(:log_to_stdout=)
如果使用Puma作为应用服务器,需要在config/puma.rb中追加配置,避免Puma重定向输出:
# 把Puma的标准输出、错误输出都直接打到当前进程STDOUT/STDERR,开启同步刷新 stdout_redirect STDOUT, STDERR, true
配置修改完成后重启应用进程,Rails.logger.info输出的日志就可以同时在kubectl logs和Datadog平台正常查询。
内容的提问来源于stack exchange,提问作者Priya
相关产品推荐
相关产品推荐

