Java Tracker - OXYGEN-MARKET/oxygen-market.github.io GitHub Wiki
HOME » SNOWPLOW TECHNICAL DOCUMENTATION » Trackers » Android/Java Tracker
This page refers to version 0.8.0+ of the Snowplow Java Tracker.
- 1 Overview
- 2 Initialization
- 3 Adding extra data: the Subject class
- 3.1
setUserId
- 3.2
setScreenResolution
- 3.3
setViewport
- 3.4
setColorDepth
- 3.5
setTimezone
- 3.6
setLanguage
- 3.7
setIpAddress
- 3.8
setUseragent
- 3.9
setNetworkUserId
- 3.10
setDomainUserId
- 3.1
- 4 Tracking specific events
- 4.1 Common
- 4.1.1 Self-describing JSON
- 4.1.2 Custom contexts
- 4.1.3 Timestamp override
- 4.1.4 Subject override
- 4.1.5 Event ID override
- 4.2
track(ScreenView event)
- 4.3
track(PageView event)
- 4.4
track(EcommerceTransaction event)
- 4.4.1
EcommerceTransactionItem
- 4.4.1
- 4.5
track(Structured event)
- 4.6
track(Unstructured event)
- 4.7
track(Timing event)
- 4.1 Common
- 5 Sending event:
Emitter
- 5.1
HttpClientAdapter
- 5.1.1
OkHttpClientAdapter
- 5.1.2
ApacheHttpClientAdapter
- 5.1.1
- 5.2 Using a buffer
- 5.3 Choosing the HTTP method
- 5.4 Thread Count
- 5.5 Emitter callback
- 5.1
- 6 Payload
- 6.1 TrackerPayload
- 6.2 SelfDescribingJson
- 7 Logging
The Snowplow Java Tracker allows you to track Snowplow events from your Java-based desktop and server apps, servlets and games. It supports JDK7+.
The tracker should be straightforward to use if you are comfortable with Java development. If you haven't already, have a look at the Java Tracker Setup or Android Tracker Setup guide before continuing.
Assuming you have completed the Java Tracker Setup for your project, you are now ready to initialize the Java Tracker.
Import the Java Tracker's classes into your Java code like so:
import com.snowplowanalytics.snowplow.tracker.*;
import com.snowplowanalytics.snowplow.tracker.emitter.*;
import com.snowplowanalytics.snowplow.tracker.http.*;
That's it - you are now ready to initialize a Tracker instance.
To instantiate a tracker in your code (can be global or local to the process being tracked) simply instantiate the Tracker
interface with the following builder patterm:
Tracker.TrackerBuilder(Emitter : emitter, String : namespace, String : appId)
.subject(Subject)
.base64(boolean)
.platform(enum DevicePlatforms)
.build();
For example:
Tracker tracker = new Tracker.TrackerBuilder(emitter, "AF003", "cf")
.subject(user1Subject)
.base64(true)
.platform(DevicePlatform.Desktop)
.build();
Argument Name | Description | Required? | Default |
---|---|---|---|
emitter |
The Emitter object you create | Yes | Null |
namespace |
The name of the tracker instance | Yes | Null |
appId |
The application ID | Yes | Null |
subject |
The subject that defines a user | No | Null |
base64 |
Whether to enable base 64 encoding | No | True |
platform |
The device the Tracker is running on | No | ServerSideApp |
The emitter to which the tracker will send events. See Emitters for more on emitter configuration.
To attach a new Emitter to the Tracker:
Emitter newEmitter = ...;
tracker.setEmitter(newEmitter);
The user which the Tracker will track. This should be an instance of the Subject class. You don't need to set this during Tracker construction; you can use the Tracker.setSubject
method afterwards. Alternatively, you can also include a Subject object with the actual event; this will override the Tracker attached subject.
In fact, you don't need to create a subject at all. If you don't, though, your events won't contain user-specific data such as timezone and language.
To attach a new Subject to the Tracker:
Subject newSubject = ...;
tracker.setSubject(newSubject);
The namespace
argument will be attached to every event fired by the new tracker. This allows you to later identify which tracker fired which event if you have multiple trackers running.
To set a new Namespace in the Tracker:
tracker.setNamespace("New-Namespace");
The appId
argument lets you set the application ID to any string.
To set a new AppId in the Tracker:
tracker.setAppId("New-App-Id");
By default, unstructured events and custom contexts are encoded into Base64 to ensure that no data is lost or corrupted. You can turn encoding on or off using the boolean base64
argument.
To change whether to base64 encode:
tracker.setBase64Encoded(true || false);
By default this value is set to DevicePlatform.ServerSideApp
.
You can change the platform by calling:
tracker.setPlatform(DevicePlatform.{{ Enum value }});
For a full list of supported platforms, please see the Snowplow Tracker Protocol.
You may have additional information about your application's environment, current user and so on, which you want to send to Snowplow with each event.
The Subject class has a set of set...()
methods to attach extra data relating to the user to all tracked events:
setUserId
setScreenResolution
setViewport
setColorDepth
setTimezone
setLanguage
setIpAddress
setUseragent
setNetworkUserId
setDomainUserId
Here are some examples:
// Init an empty Subject and add some values
Subject s1 = new Subject.SubjectBuilder().build();
s1.setUserId("Kevin Gleason");
s1.setLanguage("en-gb");
s1.setScreenResolution(1920, 1080);
// Init all values at build time
Subject s1 = new Subject.SubjectBuilder()
.userId("Kevin Gleason")
.language("en-gb")
.screenResolution(1920, 1080)
.build();
After that, you can add your Subject to your Tracker like so:
Tracker t1 = new Tracker.TrackerBuilder( ... )
.subject(s1)
.build();
// OR
t1.setSubject(s1);
You can set the user ID to any string:
s1.setUserId( "{{USER ID}}" )
Example:
s1.setUserId("alexd")
If your Java code has access to the device's screen resolution, then you can pass this in to Snowplow too:
t1.setScreenResolution( {{WIDTH}}, {{HEIGHT}} )
Both numbers should be positive integers; note the order is width followed by height. Example:
t1.setScreenResolution(1366, 768)
If your Java code has access to the viewport dimensions, then you can pass this in to Snowplow too:
s.setViewport( {{WIDTH}}, {{HEIGHT}} )
Both numbers should be positive integers; note the order is width followed by height. Example:
s.setViewport(300, 200)
If your Java code has access to the bit depth of the device's color palette for displaying images, then you can pass this in to Snowplow too:
s.setColorDepth( {{BITS PER PIXEL}} )
The number should be a positive integer, in bits per pixel. Example:
s.setColorDepth(32)
This method lets you pass a user's timezone in to Snowplow:
s.setTimezone( {{TIMEZONE}} )
The timezone should be a string:
s.setTimezone("Europe/London")
This method lets you pass a user's language in to Snowplow:
s.setLanguage( {{LANGUAGE}} )
The language should be a string:
s.setLanguage('en')
This method lets you pass a user's IP Address in to Snowplow:
setIpAddress( {{IP ADDRESS}} )
The IP address should be a string:
subj.setIpAddress("127.0.0.1");
This method lets you pass a useragent in to Snowplow:
setUseragent( {{USERAGENT}} )
The useragent should be a string:
subj.setUseragent("Agent Smith");
This method lets you pass a Network User ID in to Snowplow:
setNetworkUserId( {{NUID}} )
The network user id should be a string:
subj.setNetworkUserId("network-id");
This method lets you pass a Domain User ID in to Snowplow:
setDomainUserId( {{DUID}} )
The domain user id should be a string:
subj.setDomainUserId("domain-id");
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.
Events supported by the Java Tracker at a glance:
Events | *Description |
---|---|
track(ScreenView event) |
Track the user viewing a screen within the application |
track(PageView event) |
Track and record views of web pages |
track(EcommerceTransaction event) |
Track an ecommerce transaction and its items |
track(Structured event) |
Track a Snowplow custom structured event |
track(Unstructured event) |
Track a Snowplow custom unstructured event |
track(Timing event) |
Track a Timing with Category event |
You can also directly Track a TrackerPayload
object. Please only use this function to re-track failed event payloads.
tracker.track(aTrackerPayload);
All events are tracked with specific methods on the tracker instance, of the form track(XXX)
, where XXX
is the type of event to track.
A SelfDescribingJson
is used as a wrapper around either a TrackerPayload
, another SelfDescribingJson
or a Map
object. After creating the object you want to wrap, you can create a SelfDescribingJson
using the following:
// This is the Map we have created
Map<String, String> eventData = new HashMap<>();
eventData.put("Event", "Data")
// We wrap that map in a SelfDescribingJson before sending it
SelfDescribingJson json = new SelfDescribingJson("iglu:com.acme/example/jsonschema/1-0-0", eventData);
You can create a SelfDescribingJson with the following arguments:
Argument | Description | Required? | Type |
---|---|---|---|
schema |
JsonSchema that describes the data | Yes | String |
data |
Data that will be validated by the schema | No | Map, TrackerPayload, SelfDescribingJson |
SelfDescribingJson
is used for recording custom contexts and unstructured events.
In short, custom contexts let you add additional information about the circumstances surrounding an event in the form of a Map object. Each tracking method accepts an additional optional contexts parameter:
t1.track(PageView.builder().( ... ).customContext(List<SelfDescribingJson> context).build());
The customContext
argument should consist of a List
of SelfDescribingJson
representing an array of one or more contexts. The format of each individual context element is the same as for an unstructured event.
If a visitor arrives on a page advertising a movie, the context dictionary might look like this:
{
"schema": "iglu:com.acme_company/movie_poster/jsonschema/2-1-1",
"data": {
"movie_name": "Solaris",
"poster_country": "JP",
"poster_year": "1978"
}
}
To construct this as a SelfDescribingJson
:
// Create a Map of the data you want to include...
Map<String, String> dataMap = new HashMap<>();
dataMap.put("movie_name", "solaris");
dataMap.put("poster_country", "JP");
dataMap.put("poster_year", "1978");
// Now create your SelfDescribingJson object...
SelfDescribingJson context1 = new SelfDescribingJson("iglu:com.acme/movie_poster/jsonschema/2.1.1", dataMap);
// Now add this JSON into a list of SelfDescribingJsons...
List<SelfDescribingJson> contexts = new ArrayList<>();
contexts.add(context1);
Note that even if there is only one custom context attached to the event, it still needs to be placed in an array.
In all the trackers, we offer a way to override the timestamp if you want the event to show as tracked at a specific time. If you don't, we create a timestamp while the event is being tracked.
Here is an example:
t1.track(PageView.builder().( ... ).timestamp(1423583655000).build());
In this tracker, we offer a way to attach an event specific Subject
if you want the event to be specific to a certain user. If you don't, we attempt to attach the Tracker subject or no Subject if neither are available.
This is useful for quickly overriding the Tracker subject for specific users.
Here is an example:
t1.track(PageView.builder().( ... ).subject(aUserSubject).build());
In this tracker, we offer a way to override the event id of a specific event instead of using the automatically generated one. If you don't use this option we will simply use the auto-generated alternative.
Here is an example:
t1.track(PageView.builder().( ... ).eventId("custom-event-id").build());
Use track(ScreenView event)
to track a user viewing a screen (or equivalent) within your app. You must use either name
or id
. Arguments are:
Argument | Description | Required? | Type |
---|---|---|---|
name |
Human-readable name for this screen | No | String |
id |
Unique identifier for this screen | No | String |
customContext |
Optional custom context | No | List<SelfDescribingJson> |
timestamp |
Optional timestamp | No | Long |
eventId |
Optional custom event id | No | String |
subject |
Optional custom Subject object | No | Subject |
Examples:
t1.track(ScreenView.builder()
.name("HUD > Save Game")
.id("screen23")
.build());
t1.track(ScreenView.builder()
.name("HUD > Save Game")
.id("screen23")
.customContext(contextList)
.timestamp(1423583655000)
.eventId("uid-1")
.build());
You can use track(PageView event)
to track a user viewing a web page within your app.
Arguments are:
Argument | Description | Required? | Type |
---|---|---|---|
pageUrl |
The URL of the page | Yes | String |
pageTitle |
The title of the page | No | String |
referrer |
The address which linked to the page | No | String |
customContext |
Optional custom context | No | List<SelfDescribingJson> |
timestamp |
Optional timestamp | No | Long |
eventId |
Optional custom event id | No | String |
subject |
Optional custom Subject object | No | Subject |
Examples:
t1.track(PageView.builder()
.pageUrl("www.example.com")
.pageTitle("example")
.referrer("www.referrer.com")
.build());
t1.track(PageView.builder()
.pageUrl("www.example.com")
.pageTitle("example")
.referrer("www.referrer.com")
.customContext(contextList)
.timestamp(1423583655000)
.eventId("uid-1")
.build());
Use track(EcommerceTransaction event)
to track an ecommerce transaction.
Arguments:
Argument | Description | Required? | Type |
---|---|---|---|
orderId |
ID of the eCommerce transaction | Yes | String |
totalValue |
Total transaction value | Yes | Double |
affiliation |
Transaction affiliation | No | String |
taxValue |
Transaction tax value | No | Double |
shipping |
Delivery cost charged | No | Double |
city |
Delivery address city | No | String |
state |
Delivery address state | No | String |
country |
Delivery address country | No | String |
currency |
Transaction currency | No | String |
items |
Items in the transaction | Yes | List<EcommerceTransactionItem> |
items |
Items in the transaction | Yes | EcommerceTransactionItem... |
customContext |
Optional custom context | No | List<SelfDescribingJson> |
timestamp |
Optional timestamp | No | Long |
eventId |
Optional custom event id | No | String |
subject |
Optional custom Subject object | No | Subject |
The items
argument is a List
of individual EcommerceTransactionItem
elements representing the items in the e-commerce transaction or it can be a varargs
argument of many individual items. Note that track(EcommerceTransaction event)
fires multiple events: one transaction event for the transaction as a whole, and one transaction item event for each element of the items
List
. Each transaction item event will have the same timestamp, order_id, and currency as the main transaction event.
To instantiate a EcommerceTransactionItem
in your code, simply use the following constructor signature:
EcommerceTransactionItem item = EcommerceTransactionItem.builder()
.itemId("item_id")
.sku("item_sku")
.price(1.00)
.quantity(1)
.name("item_name")
.category("item_category")
.currency("currency")
.build();
These are the fields that can appear as elements in each EcommerceTransactionItem
element of the transaction item's List
:
Field | Description | Required? | Type |
---|---|---|---|
itemId |
Item ID | Yes | String |
sku |
Item SKU | Yes | String |
price |
Item price | Yes | Double |
quantity |
Item quantity | Yes | Integer |
name |
Item name | No | String |
category |
Item category | No | String |
currency |
Item currency | No | String |
customContext |
Optional custom context | No | List<SelfDescribingJson> |
timestamp |
Optional timestamp | No | Long |
eventId |
Optional custom event id | No | String |
subject |
Optional custom Subject object | No | Subject |
Example of tracking a transaction containing two items:
// Create some Transaction Items
EcommerceTransactionItem item1 = EcommerceTransactionItem.builder()
.itemId("item_id_1")
.sku("item_sku_1")
.price(1.00)
.quantity(1)
.name("item_name")
.category("item_category")
.currency("currency")
.build();
EcommerceTransactionItem item2 = EcommerceTransactionItem.builder()
.itemId("item_id_2")
.sku("item_sku_2")
.price(1.00)
.quantity(1)
.name("item_name")
.category("item_category")
.currency("currency")
.build();
// Add these items to a List
List<EcommerceTransactionItem> items = new ArrayList<>();
items.add(item1);
items.add(item2);
// Now Track the Transaction by using this list of items as an argument
tracker.track(EcommerceTransaction.builder()
.orderId("6a8078be")
.totalValue(300.00)
.affiliation("my_affiliate")
.taxValue(30.00)
.shipping(10.00)
.city("Boston")
.state("Massachusetts")
.country("USA")
.currency("USD")
.items(items)
.build());
// Or include the items as varargs in the items section
tracker.track(EcommerceTransaction.builder()
.orderId("6a8078be")
.totalValue(300.00)
.affiliation("my_affiliate")
.taxValue(30.00)
.shipping(10.00)
.city("Boston")
.state("Massachusetts")
.country("USA")
.currency("USD")
.items(item1, item2)
.build());
Use track(Structured event)
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 | String |
property |
A string describing the object or the action performed on it | No | String |
value |
A value to provide numerical data about the event | No | Double |
customContext |
Optional custom context | No | List<SelfDescribingJson> |
timestamp |
Optional timestamp | No | Long |
eventId |
Optional custom event id | No | String |
subject |
Optional custom Subject object | No | Subject |
Examples:
t1.track(Structured.builder()
.category("shop")
.action("add-to-basket")
.label("Add To Basket")
.property("pcs")
.value(2.00)
.build());
t1.track(Structured.builder()
.category("shop")
.action("add-to-basket")
.label("Add To Basket")
.property("pcs")
.value(2.00)
.customContext(contextList)
.timestamp(1423583655000)
.eventId("uid-1")
.build());
Custom unstructured events are a flexible tool that enable Snowplow users to define their own event types and send them into Snowplow.
When a user sends in a custom unstructured event, they do so as a JSON of name-value properties, that conforms to a JSON schema defined for the event earlier.
Use track(Unstructured event)
to track a custom event 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
The arguments are as follows:
Argument | Description | Required? | Type |
---|---|---|---|
eventData |
The properties of the event | Yes | SelfDescribingJson |
customContext |
Optional custom context | No | List<SelfDescribingJson> |
timestamp |
Optional timestamp | No | Long |
eventId |
Optional custom event id | No | String |
Example event json to track:
{
"schema": "iglu:com.acme/save_game/jsonschema/1-0-0",
"data": {
"levelName": "Barrels o' Fun",
"levelIndex": 23
}
}
How to set it up?
// Create a Map of your event data
Map<String, Object> eventMap = new HashMap<>();
eventMap.put("levelName", "Barrels o' Fun")
eventMap.put("levelIndex", 23);
// Create your event data
SelfDescribingJson eventData = new SelfDescribingJson("iglu:com.acme/save_game/jsonschema/1-0-0", eventMap);
// Track your event with your custom event data
t1.track(Unstructured.builder()
.eventData(eventData)
.build();
// OR
t1.track(Unstructured.builder()
.eventData(eventData)
.customContext(contextList)
.timestamp(1423583655000)
.eventId("uid-1")
.build();
For more on JSON schema, see the blog post.
Use track(Timing event)
to track an event related to a custom timing.
Argument | Description | Required? | Type |
---|---|---|---|
category |
The category of the timed event | Yes | String |
label |
The label of the timed event | No | String |
timing |
The timing measurement in milliseconds | Yes | Integer |
variable |
The name of the timed event | Yes | String |
customContext |
Optional custom context | No | List<SelfDescribingJson> |
timestamp |
Optional timestamp | No | Long |
eventId |
Optional custom event id | No | String |
Examples:
t1.track(Timing.builder()
.category("category")
.variable("variable")
.timing(1)
.label("label")
.build());
t1.track(Timing.builder()
.category("category")
.variable("variable")
.timing(1)
.label("label")
.customContext(contextList)
.timestamp(1423583655000)
.eventId("uid-1")
.build());
Events are sent using an Emitter
class. You can initialize a class using a variety of builder functions.
Here are the Emitter builder functions that can be used to make either a SimpleEmitter
or BatchEmitter
:
// Simple (GET) Emitter
Emiter simple = SimpleEmitter.builder()
.httpClientAdapter( {{ An Adapter }} ) // Required
.threadCount(20) // Default is 50
.requestCallback( {{ A callback }} ) // Default is Null
.build();
// Batch (POST) Emitter
Emiter batch = BatchEmitter.builder()
.httpClientAdapter( {{ An Adapter }} ) // Required
.bufferSize(20) // Default is 50
.threadCount(20) // Default is 50
.requestCallback( {{ A callback }} ) // Default is Null
.build();
Function Name | Description | Required? |
---|---|---|
httpClientAdapter |
The HttpClientAdapter to use for all event sending |
Yes |
bufferSize |
BatchEmitter Only: Specifies how many events go into a POST | No |
threadCount |
The count of Threads that can be used to send events | No |
requestCallback |
Lets you pass a callback class to handle succes/failure in sending events | No |
We currently offer two different Http Clients that can be used to send events to our collectors. Once created they need to be attached to the emitter in the httpClientAdapter
builder argument.
Function Name | Description | Required? |
---|---|---|
url |
The URL of the collector to send events to | Yes |
httpClient |
The http client to use (either OkHttp or Apache) | Yes |
You build an OkHttpClientAdapter
like so:
// Make a new client
OkHttpClient client = new OkHttpClient();
// Optionally configure the client
client.setConnectTimeout(5, TimeUnit.SECONDS);
client.setReadTimeout(5, TimeUnit.SECONDS);
client.setWriteTimeout(5, TimeUnit.SECONDS);
// Build the adapter
HttpClientAdapter adapter = OkHttpClientAdapter.builder()
.url("http://www.acme.com")
.httpClient(client)
.build();
You build an ApacheHttpClientAdapter
like so:
// Make a new client with custom concurrency rules
PoolingHttpClientConnectionManager manager = new PoolingHttpClientConnectionManager();
manager.setDefaultMaxPerRoute(50);
// Make the client
CloseableHttpClient client = HttpClients.custom()
.setConnectionManager(manager)
.build();
// Build the adapter
HttpClientAdapter adapter = ApacheHttpClientAdapter.builder()
.url("http://www.acme.com")
.httpClient(client)
.build();
NOTE: it is encouraged to research how best you want to setup your ApacheClient
for maximum performance. By default the Apache Client will never timeout and will also allow only two outbound connections at a time. We have used a PoolingHttpClientConnectionManager
here to override that setting to allow up to 50 concurrent outbound connections.
NOTE: Only applies to the BatchEmitter
A buffer is used to group events together in bulk before sending them. This is especially handy to reduce network usage. By default, the Emitter buffers up to 50 events before sending them. You can change this to send events instantly as soon as they are created like so:
Emiter batch = BatchEmitter.builder()
.httpClientAdapter( ... )
.build();
batch.setBufferSize(1)
The buffer size must be an integer greater than or equal to 1.
Choosing to send via GET or POST is as easy as building a particular type of Emitter. If you want to send via GET then you will need to build a SimpleEmitter
. For sending via POST you will need to build a BatchEmitter
.
The Thread Count is the size of the available Thread Pool that events can be sent on. The bigger the Pool of Threads the faster events can be sent. By default we use 50 Threads for sending but this can be altered up or down depending on many events you are sending. As well as how strong a computer the Tracker is running on.
If an event fails to send because of a network issue, you can choose to handle the failure case with a callback class to react accordingly. The callback class needs to implement the RequestCallback
interface in order to do so. Here is a sample bit of code to show how it could work:
// Make a RequestCallback
RequestCallback callback = new RequestCallback() {
@Override
public void onSuccess(int successCount) {
System.out.println("Success, successCount: " + successCount);
}
@Override
public void onFailure(int successCount, List<TrackerPayload> failedEvents) {
System.out.println("Failure, successCount: " + successCount + "\nfailedEvent:\n" + failedEvents.toString());
}
};
// Attach it to an Emitter
Emiter e1 = BatchEmitter.builder()
.httpClientAdapter( ... )
.requestCallback(callback)
.build();
In the example, we can see an in-line example of handling the case. If events are all successfully sent, the onSuccess
method returns the number of successful events sent. If there were any failures, the onFailure
method returns the successful events sent (if any) and a list of events that failed to be sent (i.e. the HTTP state code did not return 200).
A common pattern here could be to re-send all failed events if they occur. It is up to the developer to determine whether they want to wait a certain amount of time before re-sending or if they want to re-send at all.
// Example on-failure function with re-tracking
RequestCallback callback = new RequestCallback() {
@Override
public void onSuccess(int successCount) {
System.out.println("Success, successCount: " + successCount);
}
@Override
public void onFailure(int successCount, List<TrackerPayload> failedEvents) {
System.out.println("Failure, successCount: " + successCount + "\nfailedEvent:\n" + failedEvents.toString());
// Re-send each event
for (TrackerPayload payload : failedEvents) {
tracker.tracker(payload);
}
}
};
A Payload interface is used for implementing a TrackerPayload and SelfDescribingJson, but accordingly, can be used to implement your own Payload class if you choose.
A TrackerPayload is used internally within the Java Tracker to create the tracking event payloads that are passed to an Emitter to be sent accordingly. It is essentially a wrapper around a LinkedHashMap<String, String>
and does basic validation to ensure all key-value pairs are valid non-null and non-empty Strings.
A SelfDescribingJson is used primarily to ease construction of self-describing JSON objects. It is a wrapper around a LinkedHashMap<String, Object>
and will only ever contain two key-value pairs. A schema
key with a valid schema value and a data
key containing a Map
of key-value pairs.
This is used under the hood but is also useful for to know about when attaching custom contexts to events or creating Unstructured
events.
Here's a short example:
// This is the Map we have created
Map<String, String> eventData = new HashMap<>();
eventData.put("Event", "Data")
// We wrap that map in a SelfDescribingJson before sending it
SelfDescribingJson json = new SelfDescribingJson("iglu:com.acme/example/jsonschema/1-0-0", eventData);
Logging in the Tracker is done using SLF4J. The majority of the logging set as DEBUG
so it will not overly populate your own logging.