2016-09-09 13 views
5

Jak pan może wiedzieć o siebie, czasem trzeba robić zadania na żywo maszynie produkcyjnej, za pośrednictwem konsoli szyn ...Log szyny konsoli zawsze złożyć w env produkcji

ja zwykle zaczynają go z: bundle exec rails console -e production

Ale od czasu jego maszyny produkcyjnej chciałbym zalogować wszystkie pliki wyjściowe + wyjść konsoli szyny do pliku, np. do /home/sshuser/myproject/console_sessions/2016_09_09__14_33_33.txt

Ktoś wie, jak to zrobić? Chciałbym uruchomić rejestrator atuomatically, ale tylko jeśli uruchomię konsolę?

(Używam Rails 3.2) Dzięki!

+0

Możesz chcieć zacząć [ 'script'] (http : //unix.stackexchange.com/a/200642) przed uruchomieniem konsoli rails. – spickermann

+0

Dzięki, wygląda ładnie .. Ale jakoś łamie moją instalację rbenv ... nagle mam inną wersję ruby? – Lichtamberg

+3

Co powiesz na coś prostego, jak na przykład 'bundle exec rails c | i tee $ (data +"% y_% d_% m_% H_% M_% S "). Log'? –

Odpowiedz

1

Oto rozwiązanie z jednym plikiem dla całego systemu, bez modyfikacji projektów Rails i bez modyfikacji polecenia konsoli.

Można umieścić to w ~/.irbrc, testowałem go z Ruby 2.1.5 i Rails 3.2/4.0/4.2:

# ~/.irbrc for http://stackoverflow.com/questions/39411783/log-rails-console-always-to-file-in-production-env 
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 

Dla Pry, należy użyć tego ~/.pryrc:

# ~/.pryrc for http://stackoverflow.com/questions/39411783/log-rails-console-always-to-file-in-production-env 

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 

Zapisuje wejście, wyjście i błędy konsoli, a także zapytania do bazy danych do określonego pliku. Na przykład:

~/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 

wyjść Ten plik dziennika:

# 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 
+0

jakoś to nie działa dla mnie naprawdę .. nie wiem dlaczego, ale nie zaczyna się .. – Lichtamberg

+0

Czy używasz irb lub innej alternatywy (np. Pry)? Możesz dodać linię debugującą 'puts" Hello from irbrc "' jako pierwszą linię w twoim ~/.irbrc, i 'puts" Hello from irbrc/rails "' w bloku if. –

+0

Możesz też wypróbować 'ruby ~/.irbrc' w terminalu, żeby sprawdzić istnienie pliku i składnię –

2

Dokładniejsze rozwiązanie z tee byłoby:

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)'" 

Ale chciałbym lepiej napisać skrypt, nie wiem, dlaczego to problem.

1

Tworzenie nowego pliku w następującej ścieżce i będzie szyn zalogować wyjście

config/inicjalizatory/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 
Powiązane problemy