The log file can offer valuable information about what’s going on on your app.
If your app is running on a shared server, if it uses a lot of Ajax or if you’re lucky enough to have lots of traffic to your site your log can get pretty huge pretty quickly and take up valuable disc space.
One way around this is to configure Rails to only log messages with severity level ‘warn’ or higher. You can do this by adding the following to config/environments/production.rb
config.log_level = :warn
The default here is :info
but you can set any of the following: :debug
, :info
, :warn
, :error
, :fatal
, :unknown
as the default severity level.
The down-side to this method is that potentially useful information is lost.
Here’s a handy way to manage the size of your log files, take backups of your log files and keep track of specific activity all from within your app.
First, create a controller for accessing your log files:
script/generate controller log show
In this controller we need three actions: show
, backup
and destroy
.
show
to view the log, backup
to download a backup copy of the log when it starts to get too large and destroy
to clear the log when it gets too large.
These actions should look something like this:
class LogsController < ApplicationController
before_filter :login_required # => add some authentication
LOG_PATH = Rails.root.join("log", "#{RAILS_ENV}.log")
def show
@log_content = File.read(LOG_PATH)
@log_size = File.size?(LOG_PATH).to_f / 1048576 # converts file size to MB
end
def backup
send_file LOG_PATH,
:type => "text/plain",
:stream => false,
:filename => "log_backup_#{Date.today}"
end
def destroy
File.open(LOG_PATH, "w") do |log_file|
log_file.write "Log file cleared at #{Time.now}\n"
end
flash[:notice] = "log was cleared\n"
redirect_to log_path
end
end
Firstly, it’s important to have some authentication in place on these actions to prevent any e-voyeurs from peeping at your log.
LOG_PATH
is a constant we can set up to save a little repetition when referring to the log path. This will also ensure the correct log file is accessed whether you’re in development or production mode.
In the show action we’re simply setting two instance variables:
@log_content
for the log content we want to show in the view and
@log_size
to show the size of the log file in megabytes (1MB = 1,048,575 bytes).
The backup
action calls send_file()
to send the file to your computer. No redirect or render needs to be called here.
Finally, the destroy
action replaces the entire contents of the log file with the message “Log file cleared at (Time file was cleared)” and redirects to the log page.
Next we need to add routes for these actions:
# /config/routes.rb
map.resource :log, :controller => "log", :member => "backup"
To view the log we need to write the view for the show action
app/views/logs/show.html.erb:
<p>Log size: <%= "%0.3f" % @log_size %>MB</p>
<p>
<%= button_to "clear log", log_path, :method => :delete,
:confirm => "Are you sure you want to clear the log?" %> |
<%= link_to "backup log", backup_log_path %>
</p>
<pre>
<%= @log_content %>
</pre>
Here the log size is displayed in MBs to three decimal places, we have a link to “backup log” which should automatically download the log file to your computer and a button to “clear log” which asks for confirmation before clearing the log file.
The content of the log itself should be displayed in pre
tags so the white space is preserved. This helps keep it legible.
As an optional extra, we could expand on this by using a specific notation when logging information. Wrapping each message in […][…] tags.
For example:
class User < ActiveRecord::Base
after_create { |u| logger.info "[info]New user: #{u.name} was created[info]" }
end
After creating a new database entry we can log a message that reads:
“[info]New user: Jim was created[info]”
You could also add warnings with the same notation:
“[warn]User jim tried to access log file at 13:59 on June 23rd[warn]”
We can then make a few changes to the index action so we can pick out and display these messages from the log content.
class LogsController < ApplicationController
before_filter :login_required # => add some authentication
LOG_PATH = Rails.root.join("log", "#{RAILS_ENV}.log"
def show
if params[:filter]
reg_expression = Regexp.new('\[' + params[:filter] + '\](.+)\[' + params[:filter] + '\]', true)
@log_content = File.read(LOG_PATH).scan(reg_expression).join("\n")
else
@log_content = File.read(LOG_PATH)
end
@log_size = File.size?(LOG_PATH).to_f / 1048576 #converts file size to MB
end
...
end
And add links to the view:
<p>
<%= link_to "show all", log_path %> |
<%= link_to "show info", log_path(:filter => "info") %> |
<%= link_to "show warnings", log_path(:filter => "warn") %>
</p>
Now, by clicking “show info” or “show warnings” we can see a quick list of all the custom messages we’ve logged.