我想在不重新启动应用程序的情况下更改正在运行的 Rails 3.2.x 应用程序的日志记录级别。我的目的是使用它来进行短时调试和信息收集,然后再将其恢复到通常的日志记录级别。
我还了解,按升序排列的级别是调试、信息、警告、错误和致命,生产服务器记录信息及更高,而开发日志调试及更高。
我明白,如果我跑步
Rails.logger.level=:debug #or :info, :warn, :error, :fatal
这会立即更改日志记录级别吗?
如果是这样,我可以通过编写 Rake 任务来调整日志记录级别来做到这一点,还是需要通过添加路由来支持这一点?例如在config/routes.rb中:
match "/set_logging_level/:level/:secret" => "logcontroller#setlevel"
,然后在日志控制器中设置级别。(:level 是日志记录级别,客户端和服务器之间共享的 :secret 是防止随机用户调整日志级别的东西)
耙子任务和/set_logging_level哪个更合适?
为什么不使用操作系统信号呢?例如,在 UNIX 上,user1 和 user2 信号可以自由用于您的应用程序:
config/initializers/signals.rb:
trap('USR1') do
Rails.logger.level = Logger::DEBUG
end
trap('USR2') do
Rails.logger.level = Logger::WARN
end
然后只需这样做:
kill -SIGUSR1 pid
kill -SIGUSR2 pid
只要确保你没有覆盖服务器的信号 - 每个服务器都利用各种信号来执行日志轮换、子进程终止和终止等操作。
在 Rails 控制台中,您可以简单地执行以下操作:
Rails.logger.level = :debug
现在,所有执行的代码都将使用此日志级别运行
由于您必须更改正在运行的轨道实例中的级别,因此简单的 rake 任务将不起作用。
我会选择专用路线。
而不是共享密钥,我将使用应用程序的标准用户身份验证(如果您的应用程序有用户)并限制管理员/超级用户的访问。
在你的控制器日志控制器中试试这个
def setlevel
begin
Rails.logger.level = Logger.const_get(params[:level].upcase)
rescue
logger.info("Logging level #{params[:level]} not supported")
end
end
你也可以使用 gdb 附加到正在运行的进程,将 Rails.logger 设置为调试级别,然后分离。我创建了以下 1 个衬里来为我的 puma 过程执行此操作:
gdb attach $(pidof puma) -ex 'call(rb_eval_string("Rails.logger.level = Logger::DEBUG"))' -ex detach -ex quit
注意:pidof 将按降序返回多个 pid。因此,如果您有多个同名进程,则只会在 pidof 返回的第一个进程上运行。其他的将被"gdb attach"命令丢弃,并显示消息:"忽略多余的命令行参数。(26762)".但是,如果您只关心pidof返回的第一个进程,则可以安全地忽略它。
使用 rufus-scheduler,我创建了这个调度:
scheduler.every 1.second do
file_path = "#{Rails.root}/tmp/change_log_level.#{Process.pid}"
if File.exists? file_path
log_level = File.open(file_path).read.strip
case log_level
when "INFO"
Rails.logger.level = Logger::INFO
Rails.logger.info "Changed log_level to INFO"
when "DEBUG"
Rails.logger.level = Logger::DEBUG
Rails.logger.info "Changed log_level to DEBUG"
end
File.delete file_path
end
end
然后,可以通过在 tmp/change_log_level.PID
下创建一个文件来更改日志级别,其中 pid
是 rails 进程的进程 ID。您可以创建 rake/capistrano 任务来检测和创建这些文件,从而快速切换正在运行的生产服务器的日志级别。
只要记住在工作线程中启动rufus,如果你使用的是独角兽或类似的东西。
我认为这是一个很好的例子,可以放在动态配置系统之上。动态配置负责将日志级别实时传播到服务器,然后在发生日志记录时,它可以评估日志级别的当前状态。大多数 FeatureFlags 产品都以类似的方式推送这样的新配置。
这样做的优点是,除了简单的全局日志级别之外,您还可以拥有带有规则的更复杂的 LogLevel 对象。这使您可以为Services::Billing
类90 minutes
打开DEBUG
user1234
。
我已经考虑到这一点构建了 prefab.cloud,因此值得一试。动态日志记录的核心 ruby 代码是 https://github.com/prefab-cloud/prefab-cloud-ruby/blob/main/lib/prefab/logger_client.rb
简化,这是:
def log(message, path, progname, severity)
severity ||= ::Logger::UNKNOWN
return true if severity < level_of(@dynamic_config.get(path, @context))
...log as normal...
end
如果您不想使用预制件,则可以使用另一个动态配置系统来执行类似操作。