Snowplow Android Tracker 1.2.0 released with global contexts


IMPORTANT NOTE: 1.2.0 has a critical bug which causes duplication of natively supported contexts. 1.2.1 release is published to patch this bug. Thanks for the understanding.

We are pleased to announce the 1.2.0 release of the Snowplow Android Tracker.

1.2.0 introduces support for global contexts: a set of new functions enabling users to send custom contexts with every event or a subset of events based on user provided criteria.

Read on for:

  1. Global Contexts
  2. Customizable Emitter timeout
  3. Other updates
  4. Documentation
  5. Getting help

1. Global Contexts

1.1 A quick recap on contexts

One of the most powerful features in Snowplow is support for contexts. Contexts are entities that are tracked across multiple events. Examples of contexts include:

Contexts have a few features:

With Snowplow:

1.2 Introducing “global contexts”

Until recently developers integrating Snowplow tracking had to attach contexts to each event.

With “global contexts”, it is now possible for developers to ensure that contexts are automatically attached to all events, or a subset. This presents a number of benefits:

  1. It makes it easier for developers to implement Snowplow to track very rich data in an easy way.
  2. It makes the tracking less error-prone – it is not significantly less likely that an event will accidentally be sent without a required context attached.
  3. That in turn makes it easier for analysts and developers consuming the data, because they can be confident to expect certain events from particular platforms to always have the required contexts attached.

Global contexts were introduced in the Javascript tracker in version 2.10.0. This release of the Android tracker adds Global contexts to Android. We plan to release similar functionality for iOS apps in a forthcoming release of our Objective-C Tracker.

1.3 Getting started with global contexts

1.3.1 Context Primitives

Context primitives are the simplest forms to represent global contexts and there are 2 forms: Self describing JSON & Context Generator. Self Describing JSON

Custom contexts have been represented as self describing JSONs so far and they can be used directly as a global context when you’d like a context to be attached to every event.

Map<String, String> attributes = new HashMap<>(); attributes.put("test-key-1", "test-value-1"<span class="o">); GlobalContext testCtx = new SelfDescribingJson("sdjExample", "iglu:com.snowplowanalytics.snowplow/test_event/jsonschema/1-0-1", attributes<span class="o">); tracker.addGlobalContext(testCtx<span class="o">);

Have you noticed the first argument of SelfDescribingJson above? With this release SelfDescribingJson class offers new constructors with a new parameter, tag, to be used to identify global contexts. All existing constructors of the class are kept to stay backward compatible. Context Generator

A context generator is a callback that returns a self describing JSON, representing a context. They are evaluated each time an event is sent, hence they meet the case where we would like to send a context based on event payload.

GlobalContext testCtx = new ContextGenerator() { @Override public SelfDescribingJson generate(TrackerPayload payload, String eventType, String eventSchema) { if (payload.getMap().get("aid").equals("web_app")) { return new SelfDescribingJson("iglu:com.acme/web_example/jsonschema/1-0-0"<span class="o">); } else { return new SelfDescribingJson("iglu:com.acme/generic_example/jsonschema/1-0-0"<span class="o">); } } @Override public String tag() { return "testCtx"<span class="o">
; } <span class="o">}; tracker.addGlobalContext(testCtx<span class="o">);

Callbacks are represented as interfaces in Java, hence ContextGenerator is an interface and it is required to implement ContextGenerator interface by defining generate and tag methods. generate function will be evaluated for each event sent from tracker and the returned Self Describing JSON will be attached to the event. tag is the identifier of this global context.

Let us explain the generate method in detail. Signature is SelfDescribingJson generate(TrackerPayload payload, String eventType, String eventSchema).

1.3.2 Conditional Context Providers

While Context Generator is technically capable of handling what Conditional Context Providers can offer, we want to ease the handling of conditional cases as following. Filter Provider

A Filter Provider is used to discriminate between events so we can attach global contexts only to certain events.

ContextPrimitive primitive = new SelfDescribingJson("iglu:com.acme/test_event/jsonschema/1-0-0"<span class="o">); GlobalContext testCtx = new FilterProvider("test-tag", new ContextFilter() { @Override public boolean filter(TrackerPayload payload, String eventType, String eventSchema) { return eventType.equals("se"<span class="o">); } }, primitive<span class="o">); tracker.addGlobalContext(testCtx<span class="o">);

Here is the constructor signature: FilterProvider(String tag, ContextFilter contextFilter, ContextPrimitive contextPrimitive)

Let’s look at the signature of ContextFilter’s filter, boolean filter(TrackerPayload payload, String eventType, String eventSchema).

FilterProvider also offers another constructor with only difference in the 3rd parameter as following; List<ContextPrimitive> contextPrimitives. RuleSet Provider

A Ruleset Provider is used when you want to attach a global context to certain events based on the schema URI.

Here is the constructor signature: RuleSetProvider(String tag, RuleSet ruleSet, ContextPrimitive contextPrimitive)

RuleSet stores allowed and rejected URIs. Here is the signature of its constructor: RuleSet(String accept, String reject) . Plural version is also available.

accept and reject are strings very similar to Iglu URIs with the exception that a wildcard can be used in an allowed fashion to refer to all applying cases.

The parts of a rule are wildcarded with certain guidelines:

2. Customizable Emitter timeout

The emitter timeout now can be customized thanks to the contribution by @antonkazakov!

Emitter e2 = new Emitter .EmitterBuilder("com.collector.acme", context) .emitTimeout(5) .build<span class="o">();

3. Other updates

Other updates and fixes include:

4. Documentation

As always, information about how to use the tracker can be found in the Android Tracker documentation.

You can find the full release notes on GitHub as Snowplow Android Tracker 1.2.0 release.

5. Getting help

For help on integrating the tracker please have a look at the documentation.

If you have any questions or run into any problems, please visit our Discourse forum. As always, do raise any bugs in the Android Tracker’s issues on GitHub.

For more details on this release, please check out the release notes on GitHub.


Related articles