Skip to content

Common opnionated code for audit logs and statistcs tracking for Rails apps, via ActiveSupport instrumentation.

License

Notifications You must be signed in to change notification settings

myfreecomm/nexaas-auditor

Repository files navigation

Nexaas::Auditor

Build Status Test Coverage Code Climate

Common opnionated code for audit logs and statistcs tracking for Rails apps, via ActiveSupport instrumentation. Used in production in a few Nexaas systems.

This has been tested with Rails 4.2.x only so far. It probably works fine as well in Rails 4.1.x, but I'm not sure about Rails 3.x yet. It requires Ruby v2.2.3 at least (but we recommend using v2.3.x).

The audit log is created in a logfmt format only for now. Support for more log formats is planned in the future.

Both the audit log and statistics tracking assume all instrumented events are named in a dot notation format, for example you could use 'app.users.login.sucess' to instrument a successful user login event. The 'app.' prefix is a suggestion to separate your business-logic events from framework-specific (Rails) events, which will always have a 'rails.' prefix, for example 'rails.action_controller.runtime.total' for example.

Installation

Add this line to your application's Gemfile:

gem 'nexaas-auditor'

And then execute:

$ bundle

Or install it yourself as:

$ gem install nexaas-auditor

Usage

In a Rails initializer file such as config/initializers/nexaas_auditor.rb, put something like this:

require 'nexaas/auditor'

Nexaas::Auditor.configure do |config|
  config.enabled = true
  config.logger = Rails.logger

  # use audit logging for business-logic instrumented events
  config.log_app_events = true

  # use statistics tracking for business-logic instrumented events
  config.track_app_events = true

  # use statistics tracking for default Rails instrumented events
  # don't forget to add the 'nunes' gem to your Gemfile (we use Nunes to do the
  # heavy lifting on the instrumented Rails events)
  config.track_rails_events = false

  # optionally, prepend statistics metric names with your app name. use this if
  # you use the same statistics service (ie StatHat) for multiple apps.
  config.statistics_namespace = 'myappname'

  # use StatHat service if you want to
  # don't forget to add the 'stathat' gem to your Gemfile
  # config.statistics_service = 'stathat'
  # config.stathat_settings = {key: 'stathat-ez-key'}
  # the 'log' service only writes the stats to the audit log instead of
  # sending them to an external service.
  
  config.statistics_service = 'log'
  
end

# make sure all subscribers are loaded before subscribing below
Dir[Rails.root.join("app/loggers/*.rb")].each { |f| require f }
Dir[Rails.root.join("app/statistics/*.rb")].each { |f| require f }

# setup all subscribers
Nexaas::Auditor.subscribe_all

Then, create your loggers and statistic trackers in app/loggers/ and app/statistics/ for example, inheriting from Nexaas::Auditor::LogsSubscriber and Nexaas::Auditor::StatsSubscriber respectively.

For example:

class UsersAppLogger < ::Nexaas::Auditor::LogsSubscriber
  # The namespace for events to subscribe to. In this example, subscribe to all
  # events beggining with "app.users.".
  def self.pattern
    /\Aapp\.users\..+\Z/
  end

  # Called when an event with name == 'app.users.login.success' is received.
  #
  #   name = the event name, 'app.users.login.success' in this case
  #   start = the time the event started
  #   finish = the time the event finished
  #     (tip: finish - start gives you the duration in seconds as a float)
  #   event_id = an unique id for the event
  #   payload = a hash of extra data the event may have supplied when instrumented
  #
  def log_event_app_users_login_success(name, start, finish, event_id, payload)
    user_id = payload[:user_id]
    # Do the actual loggging. The `:level` and `:measure` keys are required,
    # anything else will be transformed in a key=value pair in the log string.
    logger.log(level: :info, measure: name, user_id: user_id)
  end
end

class UsersAppStatsTracker < ::Nexaas::Auditor::StatsSubscriber
  # The namespace for events to subscribe to. In this example, subscribe to all
  # events beggining with "app.users.".
  def self.pattern
    /\Aapp\.users\..+\Z/
  end

  # Called when an event with name == 'app.users.login.success' is received.
  #
  #   name = the event name, 'app.users.login.success' in this case
  #   start = the time the event started
  #   finish = the time the event finished
  #     (tip: finish - start gives you the duration in seconds as a float)
  #   event_id = an unique id for the event
  #   payload = a hash of extra data the event may have supplied when instrumented
  #
  def track_event_app_users_login_success(name, start, finish, event_id, payload)
    user_id = payload[:user_id]

    # Do the actual statistic tracking.

    # Use the `count` type to track event occurences or quantities. The `:metric`
    # key is required (generally use the name or append something to the name).
    # The `:value` should be an Integer. If `:value` is ommited it will be
    # assumed a value of 1.
    tracker.track_count(metric: name, value: 1)

    # Use the `value` type to track event durations or amounts. The `:metric`
    # key is required (generally use the name or append something to the name).
    # The `:value` key is also required and should be an Integer, Float or Decimal.
    duration = ((finish - start) * 1_000.0).round # to get the value in milliseconds
    tracker.track_value(metric: "#{name}.duration", value: duration)
  end
end

Now all that is left is for you to instrument your code to fire the events above. Following the example of logging and tracking user logins, we might have this in a hipothetical SessionsController in your app:

class SessionsController < ApplicationController
  def create
    @user = User.authenticate(session_params)
    if @user
      Nexaas::Auditor.instrument('app.users.login.success', user_id: @user.id)
      redirect_to root_path, success: "You are logged in!"
    else
      # do something else, show some error, etc
    end
  end
end

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/myfreecomm/nexaas-auditor. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.

There is a list of planned features and improvements on the TODO.md file, please read it before anything else if you want to help with nexaas-auditor development.

License

The gem is available as open source under the terms of the MIT License.

About

Common opnionated code for audit logs and statistcs tracking for Rails apps, via ActiveSupport instrumentation.

Resources

License

Code of conduct

Stars

Watchers

Forks

Packages

No packages published