Snowplow Ruby Tracker 0.3.0 released


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 SubjectVerbDirect 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 =, 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 e ="") # Create an initial Subject instance s0 = # Create a Tracker instance t =, 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 = # 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("") # 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("")

2. The Emitter class


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 ='', { :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:

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

# Create a tracker my_tracker =, '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 =[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)


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 ='') s ='user-45672').set_color_depth(24) t ='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:

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 ='', 'my_tracker_namespace', 'my_app_id') # Version 0.3.0 e ='') t =, 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!


Related articles