{"id":19474559,"url":"https://github.com/tomasc/mongoid_traffic","last_synced_at":"2026-05-15T17:02:06.150Z","repository":{"id":19658718,"uuid":"22911695","full_name":"tomasc/mongoid_traffic","owner":"tomasc","description":"Aggregated traffic logs stored in MongoDB.","archived":false,"fork":false,"pushed_at":"2018-08-15T14:24:15.000Z","size":1631,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2026-05-07T00:27:45.904Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tomasc.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-08-13T10:21:53.000Z","updated_at":"2018-08-15T14:22:58.000Z","dependencies_parsed_at":"2022-08-20T23:40:46.157Z","dependency_job_id":null,"html_url":"https://github.com/tomasc/mongoid_traffic","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/tomasc/mongoid_traffic","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tomasc%2Fmongoid_traffic","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tomasc%2Fmongoid_traffic/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tomasc%2Fmongoid_traffic/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tomasc%2Fmongoid_traffic/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tomasc","download_url":"https://codeload.github.com/tomasc/mongoid_traffic/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tomasc%2Fmongoid_traffic/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33072970,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-15T11:35:32.926Z","status":"ssl_error","status_checked_at":"2026-05-15T11:35:31.362Z","response_time":103,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-10T19:25:40.412Z","updated_at":"2026-05-15T17:02:06.113Z","avatar_url":"https://github.com/tomasc.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Mongoid Traffic\n\n[![Build Status](https://travis-ci.org/tomasc/mongoid_traffic.svg)](https://travis-ci.org/tomasc/mongoid_traffic) [![Gem Version](https://badge.fury.io/rb/mongoid_traffic.svg)](http://badge.fury.io/rb/mongoid_traffic) [![Coverage Status](https://img.shields.io/coveralls/tomasc/mongoid_traffic.svg)](https://coveralls.io/r/tomasc/mongoid_traffic)\n\nAggregated 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.\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'mongoid_traffic'\n```\n\nAnd then execute:\n\n```\n$ bundle\n```\n\nOr install it yourself as:\n\n```\n$ gem install mongoid_traffic\n```\n\n## Usage\n\nSetup your class for storing the log:\n\n```ruby\nclass MyLog\n  include Mongoid::Document\n  include MongoidTraffic::Log\nend\n```\n\nLog your traffic like this:\n\n```ruby\nMongoidTraffic::Logger.log(MyLog)\n```\n\nOr, if you prefer, directly on the `MyLog` class:\n\n```ruby\nMyLog.log\n```\n\nThis 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.\n\n### Optional arguments\n\n#### Time scope:\n\nBy default, the `.log` method creates/updates a document with aggregations for year, month, week and day. Subset of those  can be specified as:\n\n```ruby\nMyLog.log(time_scope: %i[day])\n```\n\nThe available options are: `%i[year month week day]`\n\n#### Scope:\n\nIt is possible to scope the log by an arbitrary number of parameters.\n\n```ruby\nclass MyLog\n  include Mongoid::Document\n  include MongoidTraffic::Log\n\n  belongs_to :page\n\n  scope :for_page, -\u003e (page) { where(page: page) }\nend\n```\n\nFor example:\n\n```ruby\nMongoidTraffic::Logger.log(MyLog.for_page(page))\n```\n\nor\n\n```ruby\nMyLog.for_page(page).log(page: my_page)\n```\n\nPS If you query by a scope often do not forget to add corresponding indexes to your log model.\n\n#### Arbitrary counter:\n\nIt is possible to count any number of arbitrary additional values. For example, to count unique country etc.\n\nFirst, specify the additional counter in the log model (prefer short aliased field names):\n\n```ruby\nclass MyLog\n  include Mongoid::Document\n  include MongoidTraffic::Log\n\n  additional_counter :c, as: :country\nend\n```\n\nTrack access by country as:\n\n```ruby\nMyLog.log(country: 'CZ')\nMyLog.log(country: 'NL')\n```\n\nWhich will create Hash with counts per country:\n\n```ruby\n{ _id: …, df(date_from): …, dt(date_to): …, ac(access_count): 2, c(country): { 'CZ' =\u003e 1, 'NL' =\u003e 1 } }\n```\n\nYou 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:\n\n```ruby\nclass MyLog\n  include Mongoid::Document\n  include MongoidTraffic::Log\n\n  additional_counter :b, as: :browser\nend\n```\n\nThen track access by browser as:\n\n```ruby\nMyLog.log(browser: \"Mac.Safari.8\") # log access by Mac Safari 8\nMyLog.log(browser: \"Mac.Safari.7%2E1\") # log access by Mac Safari 7.1\n```\n\nWhich will create following log document:\n\n```ruby\n{ _id: …, df(date_from): …, dt(date_to): …, ac(access_count): 2, b(browser): { 'Mac' =\u003e { 'Safari' =\u003e { '8' =\u003e 1, '7%2E1' =\u003e 1 } } } }\n```\n\nPlease note all `.` not intended to denote nesting need to be escaped (here as `%2E`).\n\n## Accessing the log\n\nThe log can be accessed using a combination of Mongoid Criteria and aggregation methods.\n\n### Criteria\n\nThe following time based criteria are predefined as Mongoid scopes:\n\n* `.day(date)`\n* `.week(week, year)`\n* `.month(month, year)`\n* `.year(year)`\n* `.for_dates(date_from, date_to)`\n\nTo select by log type:\n\n* `.daily`\n* `.weekly`\n* `.monthly`\n* `.yearly`\n\nTo narrow down by scope:\n\n* `.scoped_to(scope)`\n\n### Aggregation method\n\n* `.aggregate_on(:access_count)`\n* `.aggregate_on(ARBITRARY_COUNTER)`\n\nBehind 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).\n\n### Examples\n\n#### Time\n\n```ruby\nMyLog.day(Date.today)\n```\n\nEventually by date range (when using the `.for_dates` scope make sure to specify which log type you wish to access):\n\n```ruby\nMyLog.daily.for_dates(Date.yesterday, Date.today)\n```\n\n#### Scope\n\n```ruby\nMyLog.for_page(page).day(Date.today)\n```\n\nMake sure that the order of drilling down corresponds to the indexes on your model.\n\n#### Aggregations\n\nOn access count:\n\n```ruby\nMyLog.day(Date.today).scoped_to('/pages/123').aggregate_on(:access_count) # =\u003e 1\n```\n\nThe 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':\n\n```ruby\nMyLog.month(8, 2014).scoped_to(/\\A\\/blog/).aggregate_on(:access_count) # =\u003e 1\n```\n\nOn additional counter:\n\n```ruby\nMyLog.day(Date.today).scoped_to('/pages/123').aggregate_on(:country) # =\u003e { 'CZ' =\u003e 1, 'NL' =\u003e 1 }\n```\n\n#### Pluck\n\nFor plotting charts you might make use of standard `:pluck`:\n\n```ruby\nMyLog.daily.for_dates(Date.today - 1.week, Date.today).pluck(:date_from, :access_count) # =\u003e returns array of dates and counts per day\n```\n\n## Further reading\n\nBased 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/).\n\n## Contributing\n\n1. Fork it ( https://github.com/tomasc/mongoid_traffic/fork )\n2. Create your feature branch (`git checkout -b my-new-feature`)\n3. Commit your changes (`git commit -am 'Add some feature'`)\n4. Push to the branch (`git push origin my-new-feature`)\n5. Create a new Pull Request\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftomasc%2Fmongoid_traffic","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftomasc%2Fmongoid_traffic","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftomasc%2Fmongoid_traffic/lists"}