Snowplow Ruby Tracker 0.3.0 released

29 August 2014  •  Fred Blundun

We are happy to announce the release of the Snowplow Ruby Tracker version 0.3.0. This version adds support for asynchronous requests and POST requests, and introduces the new Subject and Emitter classes.

The rest of this post will cover:

  1. The Subject class
  2. The Emitter class
  3. Chainable methods
  4. Logging
  5. Contracts
  6. Other changes
  7. Upgrading
  8. Getting help

1. The Subject class

An instance of the Subject class represents a user who is performing an event in the Subject-Verb-Direct Object model proposed in our Snowplow event grammar. User-specific data like timezone and language are attached to instances of the Subject class.

If your tracker will only be tracking one user, you don’t have to create a Subject instance at all - one will be created automatically for you. The only change you need to make is setting the new subject argument to nil when initializing your tracker:

# Create a tracker without specifying a subject
my_tracker = Snowplow::Tracker.new(my_emitter, nil, 'my_tracker_name', 'my_app_id')

(The first argument, my_emitter, will be explained later.)

If you want more than one subject:

require 'snowplow_tracker'

# Create a simple Emitter which will log events to http://d3rkrsqld9gmqf.cloudfront.net/i
e = SnowplowTracker::Emitter.new("d3rkrsqld9gmqf.cloudfront.net")

# Create an initial Subject instance
s0 = SnowplowTracker::Subject.new

# Create a Tracker instance
t = SnowplowTracker::Tracker.new(e, s0, "cf", "CF63A")

# Set some data for the initial subject
# Events we fire will have this data attached as long as s0 is the current subject
s0.set_user_id('7834').set_lang('en')

# Create a new Subject corresponding to a pc user
s1 = SnowplowTracker::Subject.new

# Set some data for that user
s1.set_platform("pc")
s1.set_user_id("0a78f2867de")

# Set s1 as the Tracker's subject and track s1 viewing a page
# All events fired will have instead have information we set about s1 attached
# All events fired will have the information we set about s1 attached
t.set_subject(s1).track_page_view("http://www.example.com")

# Change the tracker subject from s1 back to s0
# All events fired will have instead have information we set about s0 attached
t.set_subject(s0)

# Track user s0 viewing a page
t.track_page_view("http://www.example.com")

2. The Emitter class

Overview

Each tracker instance must now be initialized with an Emitter which is responsible for firing events to a Collector. An Emitter instance is initialized with two arguments: an endpoint and an optional configuration hash. For example:

# Create an emitter
my_emitter = Snowplow::Emitter.new('d3rkrsqld9gmqf.cloudfront.net', {
  :protocol => 'https',
  :method => 'post',
  :port => 80,
  :buffer_size => 0,
  :on_success => lambda { |success_count|
    puts '#{success_count} events sent successfully'
  },
  :on_failure => lambda { |success_count, failures|
    puts '#{success_count} events sent successfully, #{failures.size} events sent unsuccessfully'
  }
})

Every setting in the configuration hash is optional. Here is what they do:

  • :protocol determines whether events will be sent using HTTP or HTTPS. It defaults to “http”
  • :method determines whether events will be sent using GET or POST. It defaults to “get”
  • :port determines the port to use
  • :buffer_size is the number of events which will be queued before they are all sent, a process called “flushing”. When using GET, it defaults to 0 because each event has its own request. When using POST, it defaults to 10, and the buffered events are all sent together in a single request
  • :on_success is a callback which is called every time the buffer is flushed and every event in it is sent successfully (meaning with status code 200). It should accept one argument: the number of requests sent this way
  • on_failure is a callback which is called if the buffer is flushed but not every event is sent successfully. It should accept two arguments: the number of successfully sent events and an array containing the unsuccessful events

Once the emitter is created, create a tracker like this:

# Create a tracker
my_tracker = Snowplow::Tracker.new(my_emitter, 'my_tracker_name', 'my_app_id')

You can then track events as in previous versions of the Ruby Tracker.

The AsyncEmitter class

The AsyncEmitter works just like the Emitter, but is asynchronous - whenever the buffer is flushed a new thread is created. This means that the requests the AsyncEmitter sends do not block.

Multiple Emitters

It is also possible to initialize a tracker with an array of emitters, in which case events will be sent to all of them:

# Create a tracker with multiple emitters
my_tracker = Snowplow::Tracker.new([my_sync_emitter, my_async_emitter], 'my_tracker_name', 'my_app_id')

You can also add new emitters after creating a tracker with the add_emitter method:

# Create a tracker with multiple emitters
my_tracker.add_emitter(another_emitter)

Flushing

You can manually flush all emitters associated with a tracker using the flush method:

# Flush all emitters
t.flush

This is useful if you are about to halt the process but do not want to lose your buffered events.

The flush method takes an optional sync argument which determines whether AsyncEmitters will be flushed synchronously. Set sync to true and the method will block until all flushing threads have finished.

3. Chainable methods

All Tracker methods and Subject methods now return self and so are chainable:

e = Snowplow::Emitter.new('d3rkrsqld9gmqf.cloudfront.net')
s = Snowplow::Subject.new.set_user_id('user-45672').set_color_depth(24)
t = Snowplow::Tracker.new(e).set_subject(s).track_screen_view('my_title_screen')

4. Logging

This release introduces logging using Ruby’s built-in Logger class. The log level is set to INFO by default but can be changed:

require 'logger'
SnowplowTracker::LOGGER.level = Logger::DEBUG

The levels are:

Level Description
FATAL Nothing logged
WARN Notification for requests with status code not equal to 200
INFO Notification for all requests
DEBUG Contents of all requests

5. Disabling contracts

The Snowplow Ruby Tracker uses the Ruby Contracts gem for typechecking. Version 0.3.0 offers the option to turn contracts on or off:

# Turn contracts off
SnowplowTracker::disable_contracts

# Turn contracts back on
SnowplowTracker::enable_contracts

6. Other changes

We have also:

  • Changed the default platform to “srv” (which is short for “server”) #37
  • Made the screen name argument to track_screen_view optional #38

7. Upgrading

There are three breaking changes to the API, two of which involving the tracker constructor: the first argument is now an Emitter rather than a Sstring, and there is a new second argument which may be a Subject but otherwise defaults to nil. An example of how to update your code:

# Version 0.2.0
t = SnowplowTracker::Tracker.new('d3rkrsqld9gmqf.cloudfront.net', 'my_tracker_namespace', 'my_app_id')

# Version 0.3.0
e = SnowplowTracker::AsyncEmitter.new('d3rkrsqld9gmqf.cloudfront.net')
t = SnowplowTracker::Tracker.new(e, nil 'my_tracker_namespace', 'my_app_id')

The final change is that all tracker methods now return the tracker instance, self.

8. Getting help

Useful links:

If you have an idea for a new feature or want help getting things set up, please get in touch. This is only the second release of the Ruby Tracker, so we’re keen to hear people’s opinions. And raise an issue if you spot any bugs!