How to install the exception_logger Rails plugin and protect the logs with basic authentication
This snippet explains how to install and use the Rails exception_logger plugin. I’ll also show you how to protect your logs by extending the plugin with basic authentication.
1 script/plugin source http://svn.techno-weenie.net/projects/plugins 2 script/plugin install exception_logger
I’m using Rails Edge on this project, so I had to install classic pagination also:
1 script/plugin install svn://errtheblog.com/svn/plugins/classic_pagination
Next create and execute the migration file:
1 ./script/generate exception_migration 2 rake db:migrate
Before starting the server we need to setup the routes:
1 map.exceptions '/logged_exceptions/:action/:id', :controller => 'logged_exceptions', :action => 'index', :id => nil
You also need to include the ExceptionLoggable in your ApplicationController:
1 class ApplicationController < ActionController::Base 2 include ExceptionLoggable 3 ...
Start your server and access the exception log at /logged_exceptions.
Exceptions can contain email addresses, passwords, credit card numbers, so you’ll want to protect /logged_exceptions from the public. This can be done by adding the following code to the end of environment.rb:
1 config.after_initialize do 2 require 'application' unless Object.const_defined?(:ApplicationController) 3 LoggedExceptionsController.class_eval do 4 before_filter :authenticate 5 6 protected 7 8 def authenticate 9 authenticate_or_request_with_http_basic do |username, password| 10 username == "foo" && password == "bar" 11 end 12 end 13 end 14 end
With this code we add a before filter that shows a login dialog to anyone trying to access /logged_exception/. Note that this requires Rails 2.0 basic authentication to work, so make sure you have the proper version installed.
Installing Ultraviolet and Oniguruma
First install Oniguruma
Oniguruma is a regular expression engine that Ultraviolet uses to parse text; Ruby also uses Oniguruma by the way. If you don’t have Oniguruma on your system you’ll get this error while installing Ultraviolet (at least on Ubuntu Linux):
1 oregexp.c:2:23: error: oniguruma.h: No such file or directory
This tells you that you should download and install Oniguruma. For me version 5.8.0 was the only version that worked, so execute this command to get the right version of Oniguruma:
1 $ wget http://www.geocities.jp/kosako3/oniguruma/archive/onig-5.8.0.tar.gz
You now have the source package on your computer, so decompress it with the following command:
1 $ tar zxvf onig-5.8.0.tar.gz
If everything went fine, change current directory:
1 $ cd onig-5.8.0/
Next, run configure:
1 $ ./configure
Watch the output closely and fix any errors reported, then run make:
1 $ make
To build and install Onigurama run:
1 $ sudo make install
I managed to get the following errors from Ultraviolet with other versions of Oniguruma, but these went away after installing 5.8.0 and re-installing Oniguruma:
1 Parsing error in // ==UserScript==: wrong number of arguments (2 for 0) #<Textpow::SyntaxNode:0xb7c91780>
Installing Ultraviolet and dependencies
Next install Ultraviolet with RubyGems:
1 $ sudo gem install -r ultraviolet --include-dependencies 2 3 Select which gem to install for your platform (i486-linux) 4 1. oniguruma 1.1.0 (mswin32) 5 2. oniguruma 1.1.0 (ruby) 6 3. Skip this gem 7 4. Cancel installation 8 > 2 9 Building native extensions. This could take a while... 10 Successfully installed ultraviolet-0.10.0 11 Successfully installed textpow-0.9.0 12 Successfully installed oniguruma-1.1.0 13 Successfully installed plist-3.0.0
Test that Ultraviolet works by running the following code with irb:
1 $ irb 2 3 require 'rubygems' 4 require 'uv' 5 puts Uv.syntaxes.join( "\n" ) 6 puts Uv.themes.join( "\n" ) 7 input = <<HTML<<HTML 8 <html> 9 <body> 10 </body> 11 </html> 12 HTMLHTML 13 14 puts Uv.parse( input, "xhtml", "html", true, "slush_poppies")
Problems
You might get this error:
1 require 'uv' 2 LoadError: libonig.so.2: cannot open shared object file: No such file or directory - /usr/lib/ruby/gems/1.8/gems/oniguruma-1.1.0/lib/oregexp.so
This message is a bit confusing. It means Ruby can’t find libonig.so.2, not oregexp.so as you could believe.
To fix this, check if the library has been linked:
1 $ ldconfig -p|grep libonig
If the library is not linked, add the path to the directory where the file is located to /etc/ld.so.conf:
1 /usr/local/lib 2 3 include /etc/ld.so.conf.d/*.conf
Then run:
1 $ ldconfig
Another way of fixing this problem would be to tell the build script to install it to /usr/lib.
Syntax highlighting code with Ruby and Ultraviolet
This site uses Ultraviolet for syntax highlighting. Ultraviolet supports 50 languages and 20 themes, so it’s sometimes difficult to pick the best theme, which is why I created the following code snippet that renders the code in all available themes and creates an HTML page displaying them all:
1 require 'uv' 2 3 language = ARGV[1] 4 input_file = ARGV[0] 5 line_numbers = true 6 output_format = "xhtml" 7 8 input = File.read(input_file) 9 10 # Render input using all available themes 11 syntax_highlighted_code = "" 12 Uv.themes.each do |theme| 13 syntax_highlighted_code << "<h2>#{theme}</h2>" 14 syntax_highlighted_code << Uv.parse( input, output_format, language, line_numbers, theme) 15 end 16 17 # Template for output file 18 page_template = <<HTML_DOC 19 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 20 21 <html> 22 <head> 23 <title>test</title> 24 #{Uv.themes.map{|theme| %Q(<link rel="stylesheet" type="text/css" href="css/#{theme}.css" />\n)}} 25 <script type="text/javascript" src=""></script> 26 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> 27 </head> 28 <body> 29 #{syntax_highlighted_code} 30 </body> 31 </html> 32 HTML_DOC 33 34 # Write highlighted text to output 35 File.open("output.html", "w") do |file| 36 file << page_template 37 end
Yes, using ERB templates would be better but interpolated strings work just fine… Save the code in highlight.rb and run it as follows:
1 highlight.rb ruby input_file.rb
Solution to "`require': no such file to load -- readline (LoadError)" problem
If you’ve compiled Ruby from source, you might get this error when executing script/console:
1 /usr/local/lib/ruby/1.8/irb/completion.rb:10:in `require': no such file to load -- readline (LoadError)
One way of fixing this is to compile readline, which is distributed along with the Ruby source:
1 cd /opt/src/ruby-1.8.5-p2/ext/readline 2 ruby extconf.rb 3 make 4 sudo make install
This works even after compiling Ruby, so no need to recompile… If you’re wondering what readline is then this quote from the project homepage sums it up in one sentence: “The GNU Readline library provides a set of functions for use by applications that allow users to edit command lines as they are typed in.”
Generate a TOC for a textile file
Takes a textile document as input (reads from a file) and generates a TOC (Table Of Contents) for it. The resulting output is a complete HTML document with the TOC and your document integrated. Requires Redcloth. Usage:
1 ruby ./textile_to_html_with_toc.rb my_textile_document.tex > my_textile_document.html
NOTE : Does not work with direct copy & paste because of a problem of correctly displaying the escaping quotes of the here document.
1 #!/usr/bin/env ruby 2 # author: marko dot haapala at aktagon dot com 3 # idea taken from here: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/134005 4 require "rubygems" 5 require "redcloth" 6 7 def generate_toc (file_name, headreg) 8 document = IO.read(file_name) 9 toc = "" 10 document.gsub(headreg) do |match| 11 number = $1 12 name = $2 13 header = name.gsub(/\s/,"+") 14 toc << '#' * number.to_i + ' "' + name + '":#' + header + "\n" 15 end 16 RedCloth.new(toc).to_html 17 end 18 19 def manipulate_body(file_name, headreg) 20 document = IO.read(file_name) 21 document.gsub!(headreg) do |match| 22 number = $1 23 name = $2 24 header = name.gsub(/\s/,"+") 25 "\nh" + number + '. <a name="' + header + '">' + name + '</a>' 26 end 27 RedCloth.new(document).to_html 28 end 29 30 if ARGV[0] == nil 31 puts "Oh no! You didn't give me a filename :(" 32 exit 1 33 end 34 35 file_name = ARGV[0] 36 headreg = /^\s*h([1-6])\.\s+(.*)/ 37 toc = generate_toc(file_name, headreg) 38 body = manipulate_body(file_name, headreg) 39 template = <<-'EOF' 40 <!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\"> 41 <html xml:lang=\"en\" lang=\"en\" xmlns=\"http://www.w3.org/1999/xhtml\"> 42 <head> 43 <title>#{file_name}</title> 44 <META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=ISO-8859-1\"> 45 <link rel=stylesheet href=\"style.css\" type=\"text/css\"> 46 </head> 47 <body> 48 #{toc} 49 #{body} 50 </body> 51 </html> 52 EOF 53 puts eval("\"" + template + "\"")