At work I was a bit disappointed there is no counter on atlasian confluence wiki. I wanted to know whether my wiki page was being read by people and didn’t want to bug the admin to install the plugin for confluence. And this would be a good occasion to play with my beloved rails.
Prerequisites for your system (here kubuntu) :
I consider that you have rails installed (else sudo apt-get install rails), and mysql (else have a look here). You’ll also need to install mysql driver. First you need to install ruby packaging system : rubygems :
wget http://rubyforge.org/frs/download.php/16452/rubygems-0.9.1.tgz
tar xzvf rubygems-0.9.1.tgz
cd rubygems-0.9.1/
sudo ruby setup.rb
Gem needs dev package aswell else you’ll land with a
ruby extconf.rb install mysql
extconf.rb:1:in `require’: no such file to load — mkmf (LoadError)
from extconf.rb:1
To fix that :
sudo apt-get install ruby1.8-dev
You’ll also need libmysqlclient12 and libmysqlclient-dev :
sudo apt-get install libmysqlclient12
wget http://security.ubuntu.com/ubuntu/pool/main/m/mysql-dfsg/libmysqlclient-dev_4.0.20-2ubuntu1.7_amd64.deb
sudo dpkg -i libmysqlclient-dev_4.0.20-2ubuntu1.7_amd64.deb
Finally you can install the driver :
sudo gem install mysql
Create your application skeleton by :
rails counter
Edit counter/config/database.yml and fill your database settings.
Now we will think about the model, what we need to keep ? IP, Browser, when the page was visited and the image visited, can’t be simpler.
ruby counter/script/generate \
model visit
Now you can edit counter/db/migrate/001_create_visits.rb that will be responsible for the database creation and future upgrades.
We will add the column we need :
class CreateVisits < ActiveRecord::Migration
def self.up
create_table :visits do |t|
t.column "ip", :string, :limit => 50, :default => "", :null => false
t.column "created_on", :timestamp, :null => false
t.column "browser_agent", :string, :limit => 100, :default => "", :null => false
t.column "resource", :string, :limit => 30
end
end
def self.down
drop_table :visits
end
end
Create the schema in mysql (either by commandline or with MySQLQuery Browser for example). Now you can create database table and columns by just running the rake goal :
cd counter
rake db:migrate
If you land on getaddrinfo: Name or service not known it’s likely that you didn’t install the mysql driver (detailed in Prerequisites section).
Ok, we have our db ready, our model, and skeletons.
We will need an image library to create the counter image. I’ll use the popular and easy to use RMagick :
sudo apt-get install libmagick9-dev
sudo apt-get install imagemagick
sudo gem install rmagick
And after some minutes you’ll end with : Successfully installed rmagick-1.15.0 On windows you’ll just need to gem install rmagick-win32
What will be doing our CounterController ? We will render an image showing number of people that requested this image, and add a line to the visits in database. I created an image with framebox public/images/frame_small.jpg to make the counter look a little bit better than a simple number. (Yeah I know I could have created it with RMagick too).
Let’s create our controller CounterController :
script/generate controller Counter
We will add the method show in CounterController (app/controllers/counter_controller.rb) :
def show
@target = @params[:id]
counter_image = \
Magick::ImageList.new("public/images/frame_small.jpg")
text = Magick::Draw.new
# We count the visitor for the given target resource
counter = Visit.count(:conditions => \
[ "resource = ?", @target])
# puts "Counter for " + @target + " - " + counter.to_s
text.annotate(counter_image, 0, 0, 0, 0, counter.to_s) {
self.gravity = Magick::CenterGravity
self.pointsize = 16
self.font_family = "Verdana"
self.stroke = ‘transparent’
self.fill = ‘red’
self.font_weight = Magick::BoldWeight
}
counter_image.format = "GIF"
counter_image = counter_image.to_blob
# The image is created, we can render it as is.
render :text => counter_image, \
:status => 200, :content_type => ‘image/gif’
end
Let’s add a filter to add a line to database, with IP… from the visitor (here we resolve the IP to get the dns which is more talkative in local network as here it contains the name of the user) :
before_filter :complete_stats, :only => :show
private
def complete_stats
@visit = Visit.new({:browser_agent => \
request.env['HTTP_USER_AGENT'], \
:ip => Resolv.getname(request.remote_ip.to_s).to_s, \
:resource => @params[:id]})
if @visit.save
#puts "Visit created"
else
#puts "Visit creation failed"
end
end
Finally you can test it (-p 80 will specify the port it turns on).
ruby script/server -p 80
You can now browse http://localhost/counter/show/imageA.gif, http://localhost/counter/show/imageB.gif, each time you visit one of them it gets incremented. Now you can insert in any confluence page a link to one of those virtual counter images and keep tracks of your visitors!
Of course this is a really simple version, but enough for my needs. You might check the referrers, count only one visit per ip per day…
You can get rails sources here (easier to read than from this wiki).