Skip to content

Scala Tracker

Anton Parkhomenko edited this page Jan 25, 2018 · 23 revisions

HOME > SNOWPLOW TECHNICAL DOCUMENTATION > Trackers > Scala Tracker

This page refers to version 0.5.0 of the Snowplow Scala Tracker. Documentation for other versions is available:

Contents

1. Overview

The Snowplow Scala Tracker allows you to track Snowplow events in your Scala apps and servers.

The tracker should be straightforward to use if you are comfortable with Scala development; any prior experience with Snowplow's Python Tracker, JavaScript Tracker, Android and Java Tracker, Google Analytics or Mixpanel (which have similar APIs to Snowplow) is helpful but not necessary.

There are three main classes which the Scala Tracker uses: subjects, emitters, and trackers.

A subject represents a single user whose events are tracked, and holds data specific to that user.

A tracker always has one active subject at a time associated with it. The default subject only has "platform=server" configured, but you can replace it with a subject containing more data. The tracker constructs events with that subject and sends them to one or more emitters, which sends them on to a Snowplow collector.

2. Initialization

2.1 Tracker

Assuming you have completed the Scala Tracker Setup, you are ready to initialize the Scala Tracker.

import scala.concurrent.ExecutionContext.Implicits.global

import com.snowplowanalytics.snowplow.scalatracker._
import com.snowplowanalytics.snowplow.scalatracker.emitters._

val emitter1 = AsyncEmitter.createAndStart("mycollector.com")
val emitter2 = new SyncEmitter("myothercollector.com", port = 8080)
val emitter3 = AsyncBatchEmitter.createAndStart(host = "myothercollector.com", port = 8080, bufferSize = 32)
val tracker = new Tracker(List(emitter1, emitter2, emitter3), "mytrackername", "myapplicationid")

The above code:

  • creates a non-blocking emitter, emitter1, with global execution context, which sends events to "mycollector.com" on the default port, port 80
  • creates a blocking emitter, emitter2, which sends events to "myothercollector.com" on port 8080
  • creates a non-blocking batch emitter3, with global execution context, which will buffer events until buffer size reach 32 events and then send all of them at once in POST request
  • creates a tracker which can be used to send events to all emitters

2.2 Subject

You can configure a subject with extra data and attach it to the tracker so that the data will be attached to every event:

val subject = new Subject()
  .setUserId("user-00035")
  .setPlatform(Desktop)
tracker.setSubject(subject)

2.3 EC2 Context

Amazon Elastic Cloud can provide basic information about instance running your app. You can add this informational as additional custom context to all sent events by enabling it in Tracker after initializaiton of your tracker:

tracker.enableEc2Context()

2.4 Google Compute Engine Metadata context

Google [Cloud Compute Engine][gce] can provide basic information about instance running your app. You can add this informational as additional custom context to all sent events by enabling it in Tracker after initializaiton of your tracker:

tracker.enableGceContext()

This will add iglu:com.google.cloud.gce/instance_metadata/jsonschema/1-0-0 context to all your events

2.5 Callbacks

All emitters supplied with Scala Tracker support callbacks invoked after every sent event (or batch of events) whether it was successful or not. This feature particularly useful for checking collector unavailability and tracker debugging.

Callbacks should have following signature:

type Callback = (CollectorParams, CollectorRequest, CollectorResponse) => Unit
  • CollectorParams is collector configuration attached to emitter
  • CollectorRequest is raw collector's payload, which can be either GET or POST and holding number of undertaken attempts
  • CollectorResponse is processed collector's response or failure reason. You'll want to pattern-match it to either no-op or notify DevOps about non-working collector

To add a callback to AsyncBatchEmitter you can use following approach:

def emitterCallback(params: CollectorParams, req: CollectorRequest, res: CollectorResponse): Unit = {
  res match {
    case TEmitter.CollectorSuccess(_) => ()
    case TEmitter.CollectorFailure(code) => 
      devopsIncident(s"Scala Tracker got unexpected HTTP code $code from ${params.getUri}")
    case TEmitter.TrackerFailure(exception) => 
      devopsIncident(s"Scala Tracker failed to reach ${params.getUri} with following exception $exception after ${req.attempt} attempt")
    case TEmitter.RetriesExceeded(failure) =>
      devopsIncident(s"Scala Tracker has stopped trying to deliver payload after following failure: $failure")
      savePayload(req)      // can be investigated and sent afterwards
  }
}
val emitter = AsyncBatchEmitter.createAndStart(collector, port, bufferSize = 32, callback = Some(emitterCallback _))

All async emitters will perform callbacks asynchronously in their ExecutionContext.

3. Sending events

Snowplow has been built to enable you to track a wide range of events that occur when users interact with your websites and apps. We are constantly growing the range of functions available in order to capture that data more richly.

Tracking methods supported by the Scala Tracker at a glance:

Since 0.5.0 self-describing events and contexts can be sent with SchemaKey wrapper from Iglu Core for additional type-safely.

val pageTypeContext = SelfDescribingJson(
  SchemaKey("com.acme", "page_type", "jsonschema", SchemaVer(1,0,0)),
  ("type" -> "promotional") ~ ("backgroundColor" -> "red")
)
t.trackPageView(url, contexts = List(pageTypeContext))

3.1 trackSelfDescribingEvent

Use trackSelfDescribingEvent to track a custom Self-describing events (previously known as Unstructured Events) which consists of a name and an unstructured set of properties. This is useful when:

  • You want to track event types which are proprietary/specific to your business (i.e. not already part of Snowplow), or
  • You want to track events which have unpredictable or frequently changing properties

You can use its alias trackUnstructEvent.

Argument Description Required? Type
unstructuredEvent Self-describing JSON containing unstructured event Yes SelfDescribingJson
contexts List of custom contexts for the event No List[SelfDescribingJson]
timestamp Device created timestamp or true timestamp No Option[Timestamp]

Create a Snowplow unstructured event self-describing JSON using the json4s DSL:

import org.json4s.JsonDSL._

val productViewEvent = SelfDescribingJson(
  "iglu:com.acme/product_view/jsonschema/1-0-0",
  ("userType" -> "tester") ~ ("sku" -> "0000013")
)

Send it using the trackSelfDescribingEvent tracker method:

tracker.trackSelfDescribingEvent(productViewEvent)

You can attach any number of custom contexts to an event:

val pageTypeContext = SelfDescribingJson(
  "iglu:com.acme/page_type/jsonschema/1-0-0",
  ("type" -> "promotional") ~ ("backgroundColor" -> "red")
)

val userContext = SelfDescribingJson(
  "iglu:com.acme/user/jsonschema/1-0-0",
  ("userType" -> "tester")
)

t.trackSelfDescribingEvent(productViewEvent, List(pageTypeContext, userContext))

3.2 trackStructEvent

Use trackStructEvent to track a custom event happening in your app which fits the Google Analytics-style structure of having up to five fields (with only the first two required).

Argument Description Required? Type
category The grouping of structured events which this action belongs to Yes String
action Defines the type of user interaction which this event involves Yes String
label A string to provide additional dimensions to the event data No Option[String]
property A string describing the object or the action performed on it No Option[String]
value A value to provide numerical data about the event No Option[Double]
contexts List of custom contexts for the event No List[SelfDescribingJson]
timestamp Device created timestamp or true timestamp No Option[Timestamp]

Example:

val pageTypeContext = SelfDescribingJson(
  "iglu:com.acme/page_type/jsonschema/1-0-0",
  ("type" -> "promotional") ~ ("backgroundColor" -> "red")
)

val userContext = SelfDescribingJson(
  "iglu:com.acme/user/jsonschema/1-0-0",
  ("userType" -> "tester")
)

t.trackStructEvent("commerce", "order", property=Some("book"), contexts=List(pageTypeContext, userContext))

3.3 trackPageView

Use trackPageView to track a user viewing a page within your app. Arguments are:

Argument Description Required? Validation
pageUrl The URL of the page Yes String
pageTitle The title of the page No Option[String]
referrer The address which linked to the page No Option[String]
contexts Custom contexts for the event No List[SelfDescribingJson]
timestamp When the pageview occurred No Option[Timestamp]

Example:

t.trackPageView("www.example.com", Some("example"), Some("www.referrer.com"))

3.4 trackError

Use trackError to track exceptions raised during your app's execution. Arguments are:

Argument Description Required? Validation
error Any throwable need to be tracked Yes Throwable
contexts Custom contexts for the event No List[SelfDescribingJson]
timestamp When the pageview occurred No Option[Timestamp]

Example:

try {
  1 / 0
} catch {
  case e: java.lang.ArithmeticException =>
    t.trackError(e)
}

Note: this tracker should not be used to track exceptions happening in tracker itself, use callbacks mechanism for that.

3.5 trackAddToCart

Use trackAddToCart to track an add-to-cart event.

3.6 trackRemoveFromCart

Use trackRemoveFromCart to track a remove-from-cart event.

3.7 trackTransaction

Use trackTransaction to record view of transaction. Fire a trackTransaction to register the transaction, and then fire trackTransactionItem to log specific data about the items that were part of that transaction.

3.8 trackTransactionItem

To track an ecommerce transaction item. Fire a trackTransaction to register the transaction, and then fire trackTransactionItem to log specific data about the items that were part of that transaction.

3.9 Setting timestamp

By default, Scala Tracker will generate a dvce_created_tstamp and add it to event payload. You also can manually set it using timestamp argument in all tracking methods. It should be in milliseconds since the Unix epoch:

tracker.trackSelfDescribingEvent(productViewEvent, Nil, Some(1432806619000L))

Beside of it, you can set true_tstamp if you have more reliable source about event timestamp. You can tag timstamp as "true" using class TrueTimestamp:

tracker.trackSelfDescribingEvent(productViewEvent, Nil, Some(Tracker.TrueTimestamp(1432806619000L)))

Now event will be sent with ttm parameter instead of dtm.

4. Subject methods

A list of the methods used to add data to the Subject class.

4.1 Set the platform with setPlatform

The default platform is Server. These are the available alternatives, all available in the package com.snowplowanalytics.snowplow.scalatracker:

Server
Web
Mobile
Desktop
Tv
Console
InternetOfThings
General

Example usage

subject.setPlatform(Tv)

4.2 Set the user ID with setUserId

You can make the user ID a string of your choice:

subject.setUserId("user-000563456")

4.3 Set the screen resolution with setScreenResolution

If your Scala code has access to the device's screen resolution, you can pass it in to Snowplow. Both numbers should be positive integers; note the order is width followed by height. Example:

subject.setScreenResolution(1366, 768)

4.4 Set the viewport dimensions with setViewport

Similarly, you can pass the viewport dimensions in to Snowplow. Again, both numbers should be positive integers and the order is width followed by height. Example:

subject.setViewport(300, 200)

4.5 Set the color depth with setColorDepth

If your Scala code has access to the bit depth of the device's color palette for displaying images, you can pass it in to Snowplow. The number should be a positive integer, in bits per pixel.

subject.setColorDepth(24)

4.6 Setting the timezone with setTimezone

If your Scala code has access to the timezone of the device, you can pass it in to Snowplow:

subject.setTimezone("Europe London")

4.7 Setting the language with setLang

You can set the language field like this:

subject.setLang("en")

4.8 Setting the IP address with setIpAddress

If you have access to the user's IP address, you can set it like this:

subject.setIpAddresss("34.634.11.139")

4.9 Setting the useragent with setUseragent

If you have access to the user's useragent (sometimes called "browser string"), you can set it like this:

subject.setUseragent("Mozilla/5.0 (Windows NT 5.1; rv:24.0) Gecko/20100101 Firefox/24.0")

4.10 Setting the domain user ID with setDomainUserId

The domain_userid field of the Snowplow event model corresponds to the ID stored in the first party cookie set by the Snowplow JavaScript Tracker. If you want to match up server-side events with client-side events, you can set the domain user ID for server-side events like this:

subject.setDomainUserId("c7aadf5c60a5dff9")

4.11 Setting the network user ID with setNetworkUserId

The network_user_id field of the Snowplow event model corresponds to the ID stored in the third party cookie set by the Snowplow Clojure Collector and Scala Stream Collector. You can set the network user ID for server-side events like this:

subject.setNetworkUserId("ecdff4d0-9175-40ac-a8bb-325c49733607")

Back to top

Clone this wiki locally
You can’t perform that action at this time.