https://github.com/tomasc/mongoid_traffic
Aggregated traffic logs stored in MongoDB.
https://github.com/tomasc/mongoid_traffic
Last synced: about 1 month ago
JSON representation
Aggregated traffic logs stored in MongoDB.
- Host: GitHub
- URL: https://github.com/tomasc/mongoid_traffic
- Owner: tomasc
- License: mit
- Created: 2014-08-13T10:21:53.000Z (almost 12 years ago)
- Default Branch: master
- Last Pushed: 2018-08-15T14:24:15.000Z (almost 8 years ago)
- Last Synced: 2026-05-07T00:27:45.904Z (about 1 month ago)
- Language: Ruby
- Homepage:
- Size: 1.56 MB
- Stars: 1
- Watchers: 3
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# Mongoid Traffic
[](https://travis-ci.org/tomasc/mongoid_traffic) [](http://badge.fury.io/rb/mongoid_traffic) [](https://coveralls.io/r/tomasc/mongoid_traffic)
Aggregated traffic logs stored in MongoDB. Fast and efficient logging via atomic updates of nested hashes in small number of MongoDB documents, semi-fast retrieveal and aggregation.
## Installation
Add this line to your application's Gemfile:
```ruby
gem 'mongoid_traffic'
```
And then execute:
```
$ bundle
```
Or install it yourself as:
```
$ gem install mongoid_traffic
```
## Usage
Setup your class for storing the log:
```ruby
class MyLog
include Mongoid::Document
include MongoidTraffic::Log
end
```
Log your traffic like this:
```ruby
MongoidTraffic::Logger.log(MyLog)
```
Or, if you prefer, directly on the `MyLog` class:
```ruby
MyLog.log
```
This will (by default) create four `MyLog` documents: each with `:df(date_from)` and `:dt(date_to)` fields specifying yearly, monthly, weekly and daily log. Each log has an `:access_count` attribute incremented with subsequent `.log` calls.
### Optional arguments
#### Time scope:
By default, the `.log` method creates/updates a document with aggregations for year, month, week and day. Subset of those can be specified as:
```ruby
MyLog.log(time_scope: %i[day])
```
The available options are: `%i[year month week day]`
#### Scope:
It is possible to scope the log by an arbitrary number of parameters.
```ruby
class MyLog
include Mongoid::Document
include MongoidTraffic::Log
belongs_to :page
scope :for_page, -> (page) { where(page: page) }
end
```
For example:
```ruby
MongoidTraffic::Logger.log(MyLog.for_page(page))
```
or
```ruby
MyLog.for_page(page).log(page: my_page)
```
PS If you query by a scope often do not forget to add corresponding indexes to your log model.
#### Arbitrary counter:
It is possible to count any number of arbitrary additional values. For example, to count unique country etc.
First, specify the additional counter in the log model (prefer short aliased field names):
```ruby
class MyLog
include Mongoid::Document
include MongoidTraffic::Log
additional_counter :c, as: :country
end
```
Track access by country as:
```ruby
MyLog.log(country: 'CZ')
MyLog.log(country: 'NL')
```
Which will create Hash with counts per country:
```ruby
{ _id: …, df(date_from): …, dt(date_to): …, ac(access_count): 2, c(country): { 'CZ' => 1, 'NL' => 1 } }
```
You can take advantage of the fact, that the underlying queries support dot-notation, and track on deeply nested hashes. For example, should you want to track access per browser:
```ruby
class MyLog
include Mongoid::Document
include MongoidTraffic::Log
additional_counter :b, as: :browser
end
```
Then track access by browser as:
```ruby
MyLog.log(browser: "Mac.Safari.8") # log access by Mac Safari 8
MyLog.log(browser: "Mac.Safari.7%2E1") # log access by Mac Safari 7.1
```
Which will create following log document:
```ruby
{ _id: …, df(date_from): …, dt(date_to): …, ac(access_count): 2, b(browser): { 'Mac' => { 'Safari' => { '8' => 1, '7%2E1' => 1 } } } }
```
Please note all `.` not intended to denote nesting need to be escaped (here as `%2E`).
## Accessing the log
The log can be accessed using a combination of Mongoid Criteria and aggregation methods.
### Criteria
The following time based criteria are predefined as Mongoid scopes:
* `.day(date)`
* `.week(week, year)`
* `.month(month, year)`
* `.year(year)`
* `.for_dates(date_from, date_to)`
To select by log type:
* `.daily`
* `.weekly`
* `.monthly`
* `.yearly`
To narrow down by scope:
* `.scoped_to(scope)`
### Aggregation method
* `.aggregate_on(:access_count)`
* `.aggregate_on(ARBITRARY_COUNTER)`
Behind the scenes, this method will take all documents returned by your criteria and combines the values of the specified field (in case of `:access_count` it is simple sum of the values, in other cases it is sum of nested hashes).
### Examples
#### Time
```ruby
MyLog.day(Date.today)
```
Eventually by date range (when using the `.for_dates` scope make sure to specify which log type you wish to access):
```ruby
MyLog.daily.for_dates(Date.yesterday, Date.today)
```
#### Scope
```ruby
MyLog.for_page(page).day(Date.today)
```
Make sure that the order of drilling down corresponds to the indexes on your model.
#### Aggregations
On access count:
```ruby
MyLog.day(Date.today).scoped_to('/pages/123').aggregate_on(:access_count) # => 1
```
The scope query accepts regular expressions, which allows for aggregations on specific parts of your site. For example should you want to query for all pages that have path beginning with '/blog':
```ruby
MyLog.month(8, 2014).scoped_to(/\A\/blog/).aggregate_on(:access_count) # => 1
```
On additional counter:
```ruby
MyLog.day(Date.today).scoped_to('/pages/123').aggregate_on(:country) # => { 'CZ' => 1, 'NL' => 1 }
```
#### Pluck
For plotting charts you might make use of standard `:pluck`:
```ruby
MyLog.daily.for_dates(Date.today - 1.week, Date.today).pluck(:date_from, :access_count) # => returns array of dates and counts per day
```
## Further reading
Based on the approach described by John Nunemaker [here](http://www.railstips.org/blog/archives/2011/06/28/counters-everywhere/) and [here](http://www.railstips.org/blog/archives/2011/07/31/counters-everywhere-part-2/).
## Contributing
1. Fork it ( https://github.com/tomasc/mongoid_traffic/fork )
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create a new Pull Request