Skip to content

Commit

Permalink
refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
tomasc committed Aug 13, 2014
1 parent e331886 commit c1a778a
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 74 deletions.
53 changes: 25 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,57 +18,54 @@ Or install it yourself as:

$ gem install mongoid_traffic

## Basic Usage
## Usage

Log your traffic like this:

Mongoid::TrafficLogger.log('/pages/123', user_agent: user_agent_string, referer: referer_string)
Mongoid::TrafficLogger.log()

Or, in case of Rails, you can use the `after_action` macro in your controllers:
Or, in case of Rails, you can use the `.after_action` macro with the `#log_traffic` helper method in your controllers:

class MyController < ApplicationController
after_action :log_traffic, only: [:show]
end

## Accessing the log

### Access count

The total number of views across all properties within a specific month can be accessed like this:

Mongoid::TrafficLog.for_year(2014).for_month(8).access_count
### Scope

The total number of views per property per specific date like this:
You can scope the log using the (optional) `scope:` argument:

Mongoid::TrafficLog.for_property('/pages/123').for_date(Date.today).access_count
Mongoid::TrafficLogger.log(scope: '/pages/123')

### User Agent
Or, in case of Rails controller:

### Referer

## Classes
class MyController < ApplicationController
after_action :log_scoped_traffic, only: [:show]
end

This gem consists of two basic classes: `MongoidTraffic::Logger` and `MongoidTraffic::Log`. The `Logger` takes care of upserting data in to the db using atomic updates, while the `Log` class is a `Mongoid::Document` class that wraps the records into neat models with scopes and helper methods for querying the log.
By default, the `:log_scoped_traffic` method scopes your log by the request path (for example '/pages/123'). You can override this with your scope like this:

## Logging
class MyController < ApplicationController
after_action { |c| c.log_scoped_traffic(scope: 'my-scope-comes-here') }, only: [:show]
end

To log traffic:
It might be good idea to use both methods in order to log access to the whole site as well as access to individual pages:

Mongoid::TrafficLogger.log(property)
class MyController < ApplicationController
after_action :log_traffic, only: [:show]
after_action :log_scoped_traffic, only: [:show]
end

Where `property` might be for example path of tracked view: `/pages/123`
## Accessing the log

This will create/update the following Mongoid month in a year:
### Access count

MongoidTraffic::Log y(year): 2014, m(month): 8, d(day): nil, rid(property): nil, ac(access_count): 1
MongoidTraffic::Log y(year): 2014, m(month): 8, d(day): nil, rid(property): /pages/123, ac(access_count): 1
The total number of views within a specific month can be accessed like this:

And for for specific date:
Mongoid::TrafficLog.for_year(2014).for_month(8).access_count

MongoidTraffic::Log y(year): 2014, m(month): 8, d(day): 13, rid(property): nil, ac(access_count): 1
MongoidTraffic::Log y(year): 2014, m(month): 8, d(day): 13, rid(property): /pages/123, ac(access_count): 1
The total number of views per scope per specific date like this:

Always tracking access to a `property` as well as an access across all properties.
Mongoid::TrafficLog.for_date(Date.today).access_count

### User Agent

Expand Down
6 changes: 3 additions & 3 deletions lib/mongoid_traffic/log.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class Log
field :m, as: :month, type: Integer
field :d, as: :day, type: Integer

field :p, as: :property, type: String
field :s, as: :scope, type: String

field :ac, as: :access_count, type: Integer
field :b, as: :browsers, type: Hash, default: {}
Expand All @@ -22,9 +22,9 @@ class Log

# ---------------------------------------------------------------------

default_scope -> { where(property: nil, year: Date.today.year, month: nil, day: nil) }
default_scope -> { where(scope: nil, year: Date.today.year, month: nil, day: nil) }

scope :for_property, -> property { where(property: property) }
scope :for_scope, -> scope { where(scope: scope) }

scope :for_year, -> year { where(year: year) }
scope :for_month, -> month { where(month: month) }
Expand Down
16 changes: 8 additions & 8 deletions lib/mongoid_traffic/logger.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,17 @@ def self.log *args

# ---------------------------------------------------------------------

def initialize property, options={}
@property = property
@options = options
def initialize scope: nil, user_agent: nil, referer: nil
@scope = scope
@user_agent_string = user_agent
@referer = referer
end

def log

%i(y ym ymd).each do |scope|
Log.collection.find(time_query(scope)).upsert(upsert_query)
Log.collection.find(property_query.merge(time_query(scope))).upsert(upsert_query)
Log.collection.find(scope_query.merge(time_query(scope))).upsert(upsert_query)
end
end

Expand Down Expand Up @@ -50,13 +51,12 @@ def browser_version

# ---------------------------------------------------------------------

def property_query
{ p: @property }
def scope_query
{ p: @scope }
end

def time_query scope
case scope
when :y then { y: Date.today.year, m: nil, d: nil }
when :ym then { y: Date.today.year, m: Date.today.month, d: nil }
when :ymd then { y: Date.today.year, m: Date.today.month, d: Date.today.day }
end
Expand All @@ -65,7 +65,7 @@ def time_query scope
private # =============================================================

def user_agent
@user_agent ||= ::UserAgent.parse(@options[:user_agent])
@user_agent ||= ::UserAgent.parse(@user_agent_string)
end

end
Expand Down
4 changes: 2 additions & 2 deletions test/mongoid_traffic/log_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ module MongoidTraffic
subject.must_respond_to :day
end

it 'has :property' do
subject.must_respond_to :property
it 'has :scope' do
subject.must_respond_to :scope
end

it 'has :access_count' do
Expand Down
57 changes: 24 additions & 33 deletions test/mongoid_traffic/logger_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

module MongoidTraffic
describe 'Logger' do
let(:property) { 'foo/bar' }
let(:scope) { 'foo/bar' }

let(:date) { Date.today }
let(:year) { date.year }
Expand All @@ -14,47 +14,38 @@ module MongoidTraffic
describe 'ClassMethods' do
describe '.log' do

describe 'when records for current date do not exist' do
before { Logger.log(property) }

describe 'for year' do
it 'creates Log for a property' do
Log.for_property(property).for_year(year).where(access_count: 1).exists?.must_equal true
end
it 'creates Log for all properties' do
Log.for_year(year).where(access_count: 1).exists?.must_equal true
end
end

describe 'for month' do
it 'creates Log for a property' do
Log.for_property(property).for_year(year).for_month(month).where(access_count: 1).exists?.must_equal true
end
it 'creates Log for all properties' do
Log.for_year(year).for_month(month).where(access_count: 1).exists?.must_equal true
end
end

describe 'for date' do
it 'creates Log for a property' do
Log.for_property(property).for_date(date).where(access_count: 1).exists?.must_equal true
end
it 'creates Log for all properties' do
Log.for_date(date).where(access_count: 1).exists?.must_equal true
end
end
end
# describe 'when records for current date do not exist' do
# before { Logger.log(scope) }

# describe 'for month' do
# it 'creates Log for a scope' do
# Log.for_scope(scope).for_year(year).for_month(month).where(access_count: 1).exists?.must_equal true
# end
# it 'creates Log for all properties' do
# Log.for_year(year).for_month(month).where(access_count: 1).exists?.must_equal true
# end
# end

# describe 'for date' do
# it 'creates Log for a scope' do
# Log.for_scope(scope).for_date(date).where(access_count: 1).exists?.must_equal true
# end
# it 'creates Log for all properties' do
# Log.for_date(date).where(access_count: 1).exists?.must_equal true
# end
# end
# end

end

describe 'user_agent' do
let(:user_agent_string) { 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10) AppleWebKit/538.46 (KHTML, like Gecko) Version/8.0 Safari/538.46' }

it 'extracts :browser_name' do
Logger.new(property, user_agent: user_agent_string).browser_name.must_equal 'Safari'
Logger.new(user_agent: user_agent_string).browser_name.must_equal 'Safari'
end
it 'extracts :browser_version' do
Logger.new(property, user_agent: user_agent_string).browser_version.must_equal '8_0'
Logger.new(user_agent: user_agent_string).browser_version.must_equal '8_0'
end
end
end
Expand Down

0 comments on commit c1a778a

Please sign in to comment.