Permalink
Browse files

initial commit

  • Loading branch information...
0 parents commit 552f19537e61140687728e280f9626ffac7a79f8 @hpdev hpdev committed Apr 7, 2011
Showing 2,301 changed files with 276,348 additions and 0 deletions.
Binary file not shown.
@@ -0,0 +1,8 @@
+nbproject
+.DS_Store
+log/*.log
+tmp/**/*
+config/database.yml
+config/resque.yml
+db/*.sqlite3
+.svn
@@ -0,0 +1,5 @@
+.DS_Store
+log/*.log
+tmp/**/*
+config/database.yml
+db/*.sqlite3
27 Gemfile
@@ -0,0 +1,27 @@
+source :rubygems
+source :rubyforge
+source :gemcutter
+source 'http://gems.github.com'
+
+gem 'rails', '2.3.5'
+gem 'json', '1.4.6'
+gem 'json_pure', '1.4.6', :require => false
+gem 'redis-namespace', '0.8.0', :require => 'redis/namespace'
+gem 'redis', '2.0.1'
+gem 'hoptoad_notifier', '2.3.7'
+gem 'rack', '1.0.1'
+gem 'mysql'
+gem 'resque', '1.9.9'
+
+group :development do
+ gem 'ruby-debug'
+end
+
+group :require_first do
+ gem 'SyslogLogger', '1.4.0', :require => 'syslog_logger'
+end
+
+group :test do
+ gem 'rspec', '1.2.9', :require => false
+ gem 'rspec-rails', '1.2.9', :require => false
+end
@@ -0,0 +1,75 @@
+GEM
+ remote: http://rubygems.org/
+ remote: http://rubygems.org/
+ remote: http://rubygems.org/
+ remote: http://gems.github.com/
+ specs:
+ SyslogLogger (1.4.0)
+ hoe (>= 1.2.0)
+ actionmailer (2.3.5)
+ actionpack (= 2.3.5)
+ actionpack (2.3.5)
+ activesupport (= 2.3.5)
+ rack (~> 1.0.0)
+ activerecord (2.3.5)
+ activesupport (= 2.3.5)
+ activeresource (2.3.5)
+ activesupport (= 2.3.5)
+ activesupport (2.3.5)
+ columnize (0.3.2)
+ hoe (2.8.0)
+ rake (>= 0.8.7)
+ hoptoad_notifier (2.3.7)
+ activesupport
+ json (1.4.6)
+ json_pure (1.4.6)
+ linecache (0.43)
+ mysql (2.8.1)
+ rack (1.0.1)
+ rails (2.3.5)
+ actionmailer (= 2.3.5)
+ actionpack (= 2.3.5)
+ activerecord (= 2.3.5)
+ activeresource (= 2.3.5)
+ activesupport (= 2.3.5)
+ rake (>= 0.8.3)
+ rake (0.8.7)
+ redis (2.0.1)
+ redis-namespace (0.8.0)
+ redis (< 3.0.0)
+ resque (1.9.9)
+ json_pure (~> 1.4.0)
+ redis-namespace (~> 0.8.0)
+ sinatra (>= 0.9.2)
+ vegas (~> 0.1.2)
+ rspec (1.2.9)
+ rspec-rails (1.2.9)
+ rack (>= 1.0.0)
+ rspec (>= 1.2.9)
+ ruby-debug (0.10.4)
+ columnize (>= 0.1)
+ ruby-debug-base (~> 0.10.4.0)
+ ruby-debug-base (0.10.4)
+ linecache (>= 0.3)
+ sinatra (1.0)
+ rack (>= 1.0)
+ vegas (0.1.8)
+ rack (>= 1.0.0)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ SyslogLogger (= 1.4.0)
+ hoptoad_notifier (= 2.3.7)
+ json (= 1.4.6)
+ json_pure (= 1.4.6)
+ mysql
+ rack (= 1.0.1)
+ rails (= 2.3.5)
+ redis (= 2.0.1)
+ redis-namespace (= 0.8.0)
+ resque (= 1.9.9)
+ rspec (= 1.2.9)
+ rspec-rails (= 1.2.9)
+ ruby-debug
@@ -0,0 +1,100 @@
+# Abacus
+
+Abacus is a simple counting server.
+It counts al kind of things as triples of strings on dates.
+
+The three parts of this service are gathered in a rails project:
+
+ 1. A resque worker using a redis queue which work as the data input interface.
+ 2. A single mysql table on which stored amounts of that triple are incremented and one Model to access the table.
+ 3. A Controller to provide an API interface to gather the stored counts with diferent sort of requests.
+
+
+## Installation
+
+- create database abacus\_statistics\_development;
+- create database abacus\_statistics\_test;
+- adjust varchar width in migration
+- bundle install
+- rake db:migrate
+- rake db:test:prepare
+- bundle exec spec spec
+- rake resque:work
+
+Intregrate this lines into the code where you want to count things:
+
+ require 'resque'
+ require 'ostruct'
+ worker = module Worker class StatisticsRecorder; @queue = 'abacus_statistics' end; end
+
+## Counting
+After running this initial installation steps you can start pushing data into the redis queue
+
+ Resque.enqueue(worker, {:ns1 => 'search', :ns2 => 'horse', :ns3 => 'website', :year => 2011, :month => 1, :day => 31})
+ Resque.enqueue(worker, {:ns1 => 'sale', :ns2 => 'horse', :ns3 => 'iphone', :year => 2011, :month => 1 , :day => 31})
+ Resque.enqueue(worker, {:ns1 => 'comment', :ns2 => 'horse', :ns3 => 'iphone', :year => 2011, :month => 1 ,:day => 31})
+
+### Save an amount > 1
+ Resque.enqueue(worker, {:ns1 => 'sales_price', :ns2 => 'horse', :ns3 => 'iphone',:amount => 2 :year => 2011, :month => 1 ,:day => 31})
+
+### Of course you can also decrement, for example if a sale is cancelled
+ Resque.enqueue(worker, {:ns1 => 'sales_price', :ns2 => 'horse', :ns3 => 'iphone',:amount => -2 :year => 2011, :month => 1 ,:day => 31})
+
+day, month, year can be skipped then the actual date is used
+ data is return as array of jason hashes
+
+### Count by post
+
+ You can also count by posting to /statistics
+ with curl this looks like this:
+ curl -d 'ns1=test_ns1&ns2=test_ns2&ns3=test_ns3' localhost:3000/statistics.json
+
+### Other languages
+
+ Everything that adds correctly formatted data to a redis queue the resque worker is listening on will work for counting.
+
+## Collecting the data
+You can receive the counts by sending http request with triples and date ranges as parameters to the webserver.
+The webserver return an Array of json hashes containing the Amount.
+
+### Get a single data set
+curl "localhost:3000/statistics?ns1=comment&ns2=horse&ns3=iphone&date_since=2011-01-31&date_till=2011-01-31&granularity=day"
+
+ [{"day":31,"ns1":"comment","month":1,"ns2":"horse","year":2011,"amount":3.0,"ns3":"iphone"}]
+
+### Get data for a date range, 0 amounts are returned for dates without data
+curl "localhost:3000/statistics?ns1=comment&ns2=horse&ns3=iphone&date_since=2011-01-29&date_till=2011-01-31&granularity=day"
+
+ [{"day":29,"ns1":"comment","month":1,"ns2":"horse","year":2011,"amount":0.0,"ns3":"iphone"},
+ {"day":30,"ns1":"comment","month":1,"ns2":"horse","year":2011,"amount":0.0,"ns3":"iphone"},
+ {"day":31,"ns1":"comment","month":1,"ns2":"horse","year":2011,"amount":1.0,"ns3":"iphone"}]
+
+### Data for multi n1, n2 and dates the cartesian product will be returned filling empty triple with 0 amount
+
+curl "http://localhost:3000/statistics?ns1\[\]=comment&ns1\[\]=sale&ns2\[\]=horse&ns2\[\]=camel&ns3=iphone&date_since=2011-01-30&date_till=2011-01-31&granularity=day"
+
+ [{"day":30,"ns1":"comment","month":1,"ns2":"horse","year":2011,"amount":0.0,"ns3":"iphone"},
+ {"day":31,"ns1":"comment","month":1,"ns2":"horse","year":2011,"amount":1.0,"ns3":"iphone"},
+ {"day":30,"ns1":"comment","month":1,"ns2":"camel","year":2011,"amount":0.0,"ns3":"iphone"},
+ {"day":31,"ns1":"comment","month":1,"ns2":"camel","year":2011,"amount":0.0,"ns3":"iphone"},
+ {"day":30,"ns1":"sale","month":1,"ns2":"horse","year":2011,"amount":0.0,"ns3":"iphone"},
+ {"day":31,"ns1":"sale","month":1,"ns2":"horse","year":2011,"amount":1.0,"ns3":"iphone"},
+ {"day":30,"ns1":"sale","month":1,"ns2":"camel","year":2011,"amount":0.0,"ns3":"iphone"},
+ {"day":31,"ns1":"sale","month":1,"ns2":"camel","year":2011,"amount":0.0,"ns3":"iphone"}]
+
+### Get data sums for month and year
+
+curl 'http://localhost:3000/statistics?ns1=comment&ns2=horse&ns3=iphone&date_since=2011-01-30&date_till=2011-01-31&granularity=month'
+
+ [{"day":null,"ns1":"comment","month":1,"ns2":"horse","year":2011,"amount":1.0,"ns3":"iphone"}]
+
+curl 'http://localhost:3000/statistics?ns1=comment&ns2=horse&ns3=iphone&date_since=2011-01-30&date_till=2011-01-31&granularity=year'
+
+ [{"day":null,"ns1":"comment","month":null,"ns2":"horse","year":2011,"amount":1.0,"ns3":"iphone"}]
+
+### Get sums of all ns3 by not using the param
+
+curl 'http://localhost:3000/statistics?ns1=comment&ns2=horse&date_since=2011-01-30&date_till=2011-01-31&granularity=year'
+
+ [{"day":null,"ns1":"comment","month":null,"ns2":"horse","year":2011,"amount":1.0,"ns3":null}]
+
@@ -0,0 +1,10 @@
+# Add your own tasks in files placed in lib/tasks ending in .rake,
+# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
+
+require(File.join(File.dirname(__FILE__), 'config', 'boot'))
+
+require 'rake'
+require 'rake/testtask'
+require 'rake/rdoctask'
+
+require 'tasks/rails'
@@ -0,0 +1,14 @@
+# Filters added to this controller apply to all controllers in the application.
+# Likewise, all the methods added will be available for all controllers.
+
+class ApplicationController < ActionController::Base
+ helper :all # include all helpers, all the time
+ protect_from_forgery :only => [:update, :delete]# See ActionController::RequestForgeryProtection for details
+
+ def index
+ docs = File.read("#{RAILS_ROOT}/README.markdown")
+ response.headers['Content-type'] = 'text/plain'
+ render :text => docs
+ end
+
+end
@@ -0,0 +1,37 @@
+class StatisticsController < ApplicationController
+
+ before_filter :check_post_params, :only => :create
+
+ def index
+ stats = Statistic.find_by_date_range(Date.parse(params[:date_since]), Date.parse(params[:date_till]), params[:ns1], params[:ns2], params[:ns3], params[:granularity])
+ hashes = stats.map{|s| s.to_hash}
+ render :json => hashes.to_json
+ end
+
+ def mean
+ stats = Statistic.find_mean_by_date_range(Date.parse(params[:date_since]), Date.parse(params[:date_till]), params[:ns1], params[:ns2], params[:ns3], params[:granularity])
+ render :json => stats.to_json
+ end
+
+ def create
+ params_to_fetch = [:ns1, :ns2, :ns3, :year, :month, :day, :amount]
+ attributes = params_to_fetch.inject({}) do |acc, key|
+ acc[key] = params[key]
+ acc
+ end
+ attributes[:amount] ||= 1
+ stat = Statistic.new(attributes)
+ stat.increment_all!
+
+ render :json => {:status => :ok}
+ end
+
+ private
+
+ def check_post_params
+ if !(params[:ns1] && params[:ns2] && params[:ns3])
+ render :status => :not_found and return
+ end
+ end
+
+end
@@ -0,0 +1,3 @@
+# Methods added to this helper will be available to all templates in the application.
+module ApplicationHelper
+end
Oops, something went wrong.

0 comments on commit 552f195

Please sign in to comment.