Log rails console always to file in production env
Log rails console always to file in production env
正如您自己所知,有时您必须通过 rails 控制台在实时生产机器上执行任务...
我通常这样开头:bundle exec rails console -e production
但由于它是生产机器,我想将 rails 控制台的所有输入和输出记录到文件 f.e。至 /home/sshuser/myproject/console_sessions/2016_09_09__14_33_33.txt
有人知道怎么做吗?
我想自动启动记录器,但前提是我 运行 控制台?
(我是运行宁Rails3.2)
谢谢!
这是一个解决方案,整个系统只有一个文件,没有修改您的 Rails 项目,也没有修改您的控制台命令。
你可以把它放在你的 ~/.irbrc 中,我用 Ruby 2.1.5 和 Rails 3.2/4.0/4.2 测试了它:
# ~/.irbrc for
if defined? Rails
puts "Loading configuration for Rails console from #{__FILE__}"
time = Time.now.strftime('%Y_%m_%d__%H_%M_%S')
log_file = File.join(Rails.root, "log", "rails_console_#{Rails.env}_#{time}.log")
#log_file = "/home/sshuser/myproject/console_sessions/#{time}.txt"
puts " logging to #{log_file}"
logger = Logger.new(log_file)
Rails.logger = logger
ActiveRecord::Base.logger = logger if defined? ActiveRecord
# Intercepts STDIN from IRB
module Readline
module History
def self.write_log(line)
Rails.logger.info(line)
end
def self.start_session_log
write_log("# session start: #{Time.now}")
at_exit { write_log(" # session stop: #{Time.now}") }
end
end
alias :old_readline :readline
def readline(*args)
ln = old_readline(*args)
begin
History.write_log("STDIN : #{ln}")
rescue
end
ln
end
end
# $stdout writes to STDOUT and Rails.logger
# $stderr writes to STDERR and Rails.logger
class MultiLog
def initialize(io)
@io = io
@desc = io.inspect[/STD\w+/]
end
def write(str)
Rails.logger.info("#{@desc} : #{str}")
@io.write(str)
end
def close
@io.close
end
end
$stdout = MultiLog.new(STDOUT)
$stderr = MultiLog.new(STDERR)
Readline::History.start_session_log
end
对于 Pry,你应该使用这个 ~/.pryrc :
# ~/.pryrc for
if defined? Rails
puts "Loading configuration for Rails console from #{__FILE__}"
time = Time.now.strftime('%Y_%m_%d__%H_%M_%S')
log_file = File.join(Rails.root, "log", "rails_console_#{Rails.env}_#{time}.log")
#log_file = "/home/sshuser/myproject/console_sessions/#{time}.txt"
puts " logging to #{log_file}"
logger = Logger.new(log_file)
Rails.logger = logger
ActiveRecord::Base.logger = logger if defined? ActiveRecord
# Intercepts STDIN from pry (from http://www.hardscrabble.net/2015/how-to-log-all-input-in-your-pry-rails-console)
class LoggingReadline
delegate :completion_proc, :completion_proc=, to: Readline
def readline(prompt)
Readline.readline(prompt).tap do |user_input|
Rails.logger.info("STDIN : #{user_input}")
end
end
end
Pry.config.input = LoggingReadline.new
# $stdout writes to STDOUT and Rails.logger
# $stderr writes to STDERR and Rails.logger
class MultiLog
# Needed for #tty?, #flush : https://github.com/pry/pry/issues/1464
def method_missing(sym,*p)
@io.send(sym,*p)
end
def initialize(io)
@io = io
@desc = io.inspect[/STD\w+/]
end
def write(str)
Rails.logger.info("#{@desc} : #{str}")
@io.write(str)
end
alias_method :print, :write
end
$stdout = MultiLog.new(STDOUT)
$stderr = MultiLog.new(STDERR)
end
它将控制台输入、输出和错误以及数据库查询保存到指定的文件中。
例如:
~/www/my_movies> bundle exec rails console -e development
Loading development environment (Rails 4.0.4)
Loading configuration for Rails console from /home/ricou/.irbrc
logging to /home/ricou/www/my_movies/log/rails_console_development_2016_10_28__11_58_41.log
2.1.5 :001 > Movie.first
=> Est - Ouest
2.1.5 :002 > puts 2+2
4
=> nil
2.1.5 :003 > exit
输出此日志文件:
# Logfile created on 2016-10-28 11:58:41 +0200 by logger.rb/44203
I, [2016-10-28T11:58:41.062811 #3860] INFO -- : # session start: 2016-10-28 11:58:41 +0200
I, [2016-10-28T11:58:46.822753 #3860] INFO -- : STDIN : Movie.first
D, [2016-10-28T11:58:46.883974 #3860] DEBUG -- : Movie Load (0.7ms) SELECT "movies".* FROM "movies" ORDER BY "movies"."id" ASC LIMIT 1
I, [2016-10-28T11:58:46.896787 #3860] INFO -- : STDOUT : => Est - Ouest
I, [2016-10-28T11:58:48.922083 #3860] INFO -- : STDIN : puts 2+2
I, [2016-10-28T11:58:48.922486 #3860] INFO -- : STDOUT : 4
I, [2016-10-28T11:58:48.922524 #3860] INFO -- : STDOUT :
I, [2016-10-28T11:58:48.922584 #3860] INFO -- : STDOUT : => nil
I, [2016-10-28T11:58:50.341326 #3860] INFO -- : STDIN : exit
I, [2016-10-28T11:58:50.342142 #3860] INFO -- : # session stop: 2016-10-28 11:58:50 +0200
tee
更准确的解决方案是:
alias railsc="TIMESTAMP=$(date +"%y_%d_%m_%H_%M_%S") eval 'bundle exec rails c > >(tee stdout_${TIMESTAMP}.log) 2> >(tee stderr_${TIMESTAMP}.log >&2)'"
不过我还是写个脚本比较好,不知道为什么会出问题。
在以下路径中创建这个新文件,它将记录 rails 输出
config/initializers/console_output.rb
if defined?(IRB::Irb)
::IRB::Irb.class_eval do
directory_name = Dir.pwd + '/console_sessions'
Dir.mkdir(directory_name) unless File.exists?(directory_name)
file_name = "#{directory_name}/#{Time.now.utc.strftime('%Y_%m_%d_%H_%M_%S')}.txt"
SYNC_CONSOLE_OUTPUT = File.new(file_name, File::WRONLY|File::CREAT|File::EXCL)
def output_value
console_output_value = sprintf(@context.return_format, @context.inspect_last_value)
$stdout.write(console_output_value)
SYNC_CONSOLE_OUTPUT.syswrite('> ' + @context.io.line(-1))
SYNC_CONSOLE_OUTPUT.syswrite(console_output_value)
end
end
end
正如您自己所知,有时您必须通过 rails 控制台在实时生产机器上执行任务...
我通常这样开头:bundle exec rails console -e production
但由于它是生产机器,我想将 rails 控制台的所有输入和输出记录到文件 f.e。至 /home/sshuser/myproject/console_sessions/2016_09_09__14_33_33.txt
有人知道怎么做吗? 我想自动启动记录器,但前提是我 运行 控制台?
(我是运行宁Rails3.2) 谢谢!
这是一个解决方案,整个系统只有一个文件,没有修改您的 Rails 项目,也没有修改您的控制台命令。
你可以把它放在你的 ~/.irbrc 中,我用 Ruby 2.1.5 和 Rails 3.2/4.0/4.2 测试了它:
# ~/.irbrc for
if defined? Rails
puts "Loading configuration for Rails console from #{__FILE__}"
time = Time.now.strftime('%Y_%m_%d__%H_%M_%S')
log_file = File.join(Rails.root, "log", "rails_console_#{Rails.env}_#{time}.log")
#log_file = "/home/sshuser/myproject/console_sessions/#{time}.txt"
puts " logging to #{log_file}"
logger = Logger.new(log_file)
Rails.logger = logger
ActiveRecord::Base.logger = logger if defined? ActiveRecord
# Intercepts STDIN from IRB
module Readline
module History
def self.write_log(line)
Rails.logger.info(line)
end
def self.start_session_log
write_log("# session start: #{Time.now}")
at_exit { write_log(" # session stop: #{Time.now}") }
end
end
alias :old_readline :readline
def readline(*args)
ln = old_readline(*args)
begin
History.write_log("STDIN : #{ln}")
rescue
end
ln
end
end
# $stdout writes to STDOUT and Rails.logger
# $stderr writes to STDERR and Rails.logger
class MultiLog
def initialize(io)
@io = io
@desc = io.inspect[/STD\w+/]
end
def write(str)
Rails.logger.info("#{@desc} : #{str}")
@io.write(str)
end
def close
@io.close
end
end
$stdout = MultiLog.new(STDOUT)
$stderr = MultiLog.new(STDERR)
Readline::History.start_session_log
end
对于 Pry,你应该使用这个 ~/.pryrc :
# ~/.pryrc for
if defined? Rails
puts "Loading configuration for Rails console from #{__FILE__}"
time = Time.now.strftime('%Y_%m_%d__%H_%M_%S')
log_file = File.join(Rails.root, "log", "rails_console_#{Rails.env}_#{time}.log")
#log_file = "/home/sshuser/myproject/console_sessions/#{time}.txt"
puts " logging to #{log_file}"
logger = Logger.new(log_file)
Rails.logger = logger
ActiveRecord::Base.logger = logger if defined? ActiveRecord
# Intercepts STDIN from pry (from http://www.hardscrabble.net/2015/how-to-log-all-input-in-your-pry-rails-console)
class LoggingReadline
delegate :completion_proc, :completion_proc=, to: Readline
def readline(prompt)
Readline.readline(prompt).tap do |user_input|
Rails.logger.info("STDIN : #{user_input}")
end
end
end
Pry.config.input = LoggingReadline.new
# $stdout writes to STDOUT and Rails.logger
# $stderr writes to STDERR and Rails.logger
class MultiLog
# Needed for #tty?, #flush : https://github.com/pry/pry/issues/1464
def method_missing(sym,*p)
@io.send(sym,*p)
end
def initialize(io)
@io = io
@desc = io.inspect[/STD\w+/]
end
def write(str)
Rails.logger.info("#{@desc} : #{str}")
@io.write(str)
end
alias_method :print, :write
end
$stdout = MultiLog.new(STDOUT)
$stderr = MultiLog.new(STDERR)
end
它将控制台输入、输出和错误以及数据库查询保存到指定的文件中。 例如:
~/www/my_movies> bundle exec rails console -e development
Loading development environment (Rails 4.0.4)
Loading configuration for Rails console from /home/ricou/.irbrc
logging to /home/ricou/www/my_movies/log/rails_console_development_2016_10_28__11_58_41.log
2.1.5 :001 > Movie.first
=> Est - Ouest
2.1.5 :002 > puts 2+2
4
=> nil
2.1.5 :003 > exit
输出此日志文件:
# Logfile created on 2016-10-28 11:58:41 +0200 by logger.rb/44203
I, [2016-10-28T11:58:41.062811 #3860] INFO -- : # session start: 2016-10-28 11:58:41 +0200
I, [2016-10-28T11:58:46.822753 #3860] INFO -- : STDIN : Movie.first
D, [2016-10-28T11:58:46.883974 #3860] DEBUG -- : Movie Load (0.7ms) SELECT "movies".* FROM "movies" ORDER BY "movies"."id" ASC LIMIT 1
I, [2016-10-28T11:58:46.896787 #3860] INFO -- : STDOUT : => Est - Ouest
I, [2016-10-28T11:58:48.922083 #3860] INFO -- : STDIN : puts 2+2
I, [2016-10-28T11:58:48.922486 #3860] INFO -- : STDOUT : 4
I, [2016-10-28T11:58:48.922524 #3860] INFO -- : STDOUT :
I, [2016-10-28T11:58:48.922584 #3860] INFO -- : STDOUT : => nil
I, [2016-10-28T11:58:50.341326 #3860] INFO -- : STDIN : exit
I, [2016-10-28T11:58:50.342142 #3860] INFO -- : # session stop: 2016-10-28 11:58:50 +0200
tee
更准确的解决方案是:
alias railsc="TIMESTAMP=$(date +"%y_%d_%m_%H_%M_%S") eval 'bundle exec rails c > >(tee stdout_${TIMESTAMP}.log) 2> >(tee stderr_${TIMESTAMP}.log >&2)'"
不过我还是写个脚本比较好,不知道为什么会出问题。
在以下路径中创建这个新文件,它将记录 rails 输出
config/initializers/console_output.rb
if defined?(IRB::Irb)
::IRB::Irb.class_eval do
directory_name = Dir.pwd + '/console_sessions'
Dir.mkdir(directory_name) unless File.exists?(directory_name)
file_name = "#{directory_name}/#{Time.now.utc.strftime('%Y_%m_%d_%H_%M_%S')}.txt"
SYNC_CONSOLE_OUTPUT = File.new(file_name, File::WRONLY|File::CREAT|File::EXCL)
def output_value
console_output_value = sprintf(@context.return_format, @context.inspect_last_value)
$stdout.write(console_output_value)
SYNC_CONSOLE_OUTPUT.syswrite('> ' + @context.io.line(-1))
SYNC_CONSOLE_OUTPUT.syswrite(console_output_value)
end
end
end