11. Analytics

11.1 Introdution

Spring XD Analytics provides support for real-time analysis of data using metrics such as counters and gauges.

We’ll look at the following metrics

Metrics can be used directly in place of a sink just as if you were creating any other stream, but you can also analyse data from an existing stream using a Tap. We’ll look at some examples of of using metrics with taps in the following sections. As a prerequisite start the XD Container as instructed in the Getting Started page.

11.2 Counter

A counter is a Metric that associates a unique name with a long value. It is primarily used for counting events triggered by incoming messages on a target stream. You create a counter with a unique name and optionally an initial value then set its value in response to incoming messages. The most straightforward use for counter is simply to count messages coming into the target stream. That is, its value is incremented on every message. This is exactly what the counter module provided by Spring XD does.

Here’s an example:

Start by creating a data ingestion stream. Something like:

$ curl -d "twittersearch --query=spring | file --directory=/tweets/" http://localhost:8080/streams/springtweets

Next, create a tap on the springtweets stream that sets a message counter named tweetcount

$ curl -d "tap @ springtweets | counter --name=tweetcount" http://localhost:8080/streams/tweettap

$ redis-cli
redis 127.0.0.1:6379> get counters.tweetcount

11.3 Field Value Counter

A field value counter is a Metric used for counting occurrences of unique values for a named field in a message payload. XD Supports the following payload types out of the box:

  • POJO (Java bean)
  • Tuple
  • JSON String

For example suppose a message source produces a payload with a field named user :

class Foo {
   String user;
   public Foo(String user) {
       this.user = user;
   }
}

If the stream source produces messages with the following objects:

   new Foo("fred")
   new Foo("sue")
   new Foo("dave")
   new Foo("sue")

The field value counter on the field user will contain:

fred:1, sue:2, dave:1

Multi-value fields are also supported. For example, if a field contains a list, each value will be counted once:

users:["dave","fred","sue"]
users:["sue","jon"]

The field value counter on the field users will contain:

dave:1, fred:1, sue:2, jon:1

field_value_counter has the following options:

fieldName
The name of the field for which values are counted (required)
counterName
A key used to access the counter values. (default: ${fieldName})

To try this out, create a stream to ingest twitter feeds containing the word spring and output to a file:

curl -d "twittersearch --query=spring | file" http://localhost:8080/streams/springtweets

Now create a tap for a field value counter:

curl -d "[email protected] | field-value-counter --fieldName=fromUser" http://localhost:8080/streams/tweettap

The twittersearch source produces JSON strings which contain the user id of the tweeter in the fromUser field. The field_value_counter sink parses the tweet and updates a field value counter named fromUser in Redis. To view the counts:

$ redis-cli
redis 127.0.0.1:6379>zrange fieldvaluecounters.fromUser 0 -1 withscores

11.4 Gauge

A guage is a Metric, similar to a counter in that it holds a single long value associated with a unique name. In this case the value can represent any numeric value defined by the application.

The gauge sink provided with XD stores expects a numeric value as a payload, typically this would be a decimal formatted string, and stores its values in Redis. The gauge includes the following attributes:

name
The name for the gauge (default: <streamname>)

Here is an example of creating a tap for a gauge:

11.4.1 Simple Tap Example

Create an ingest stream

$ curl -d "http --port=9090 | file" http://localhost:8080/streams/test

Next create the tap:

$ curl -d "[email protected] | gauge" http://localhost:8080/streams/simplegauge

Now Post a message to the ingest stream:

$ curl -d "10" http://localhost:9090

Check the gauge:

$ redis-cli
redis 127.0.0.1:6379> get gauges.simplegauge
"10"

11.5 Rich Gauge

A rich guage is a Metric that holds a double value associated with a unique name. In addition to the value, the rich guage keeps a running average, along with the minimum and maximum values and the sample count.

The richgauge sink provided with XD expects a numeric value as a payload, typically this would be a decimal formatted string, and stores its values in Redis. The richgauge includes the following attributes:

name
The name for the gauge (default: <streamname>)

The values are stored in Redis as a space delimited string, formatted as value mean max min count

Here are some examples of creating a tap for a rich gauge:

11.5.1 Simple Tap Example

Create an ingest stream

$ curl -d "http --port=9090 | file" http://localhost:8080/streams/test

Next create the tap:

$ curl -d "[email protected] | richgauge" http://localhost:8080/streams/testgauge

Now Post some messages to the ingest stream:

$ curl -d "10" http://localhost:9090
$ curl -d "13" http://localhost:9090
$ curl -d "16" http://localhost:9090

Check the gauge:

$ redis-cli
redis 127.0.0.1:6379> get richgauges.testgauge
"16.0 13.0 16.0 10.0 3"

11.5.2 Stock Price Example

In this example, we will track stock prices, which is a more practical example. The data is ingested as JSON strings like

{"symbol":"VMW","price":72.04}

Create an ingest stream

$ curl -d "http --port=9090 | file" http://localhost:8080/streams/stocks

Next create the tap, using the json-field-extractor to extract the stock price from the payload:

$ curl -d "[email protected] | json-field-extractor --fieldName=price | richgauge" http://localhost:8080/streams/stockprice

Now Post some messages to the ingest stream:

$ curl -d "{\"symbol\":\"VMW\",\"price\":72.04}" http://localhost:9000
$ curl -d "{\"symbol\":\"VMW\",\"price\":72.06}" http://localhost:9000
$ curl -d "{\"symbol\":\"VMW\",\"price\":72.08}" http://localhost:9000

Check the gauge:

$ redis-cli
redis 127.0.0.1:6379> get richgauges.stockprice
"72.08 72.04 72.08 72.02 3"

11.5.3 Improved Stock Price Example

In this example, we will track stock prices for selected stocks. The data is ingested as JSON strings like

{"symbol":"VMW","price":72.04}
{"symbol":"EMC","price":24.92}

The previous example would feed these prices to a single gauge. What we really want is to create a separate tap for each ticker symbol in which we are interested:

Create an ingest stream

$ curl -d "http --port=9090 | file" http://localhost:8080/streams/stocks

Next create the taps, using the json-field-extractor to extract the stock price from the payload:

$ curl -d "[email protected] |json-field-value-filter --fieldName=symbol --fieldValue=VMW| json-field-extractor --fieldName=price | richgauge" http://localhost:8080/streams/vmwprice
$ curl -d "[email protected] |json-field-value-filter --fieldName=symbol --fieldValue=EMC| json-field-extractor --fieldName=price | richgauge" http://localhost:8080/streams/emcprice

Now Post some messages to the ingest stream:

$ curl -d "{\"symbol\":\"VMW\",\"price\":72.04}" http://localhost:9000
$ curl -d "{\"symbol\":\"VMW\",\"price\":72.06}" http://localhost:9000
$ curl -d "{\"symbol\":\"VMW\",\"price\":72.08}" http://localhost:9000
$ curl -d "{\"symbol\":\"EMC\",\"price\":24.92}" http://localhost:9000
$ curl -d "{\"symbol\":\"EMC\",\"price\":24.90}" http://localhost:9000
$ curl -d "{\"symbol\":\"EMC\",\"price\":24.96}" http://localhost:9000

Check the gauge:

$ redis-cli
redis 127.0.0.1:6379> get richgauges.emcprice
"24.96 24.926666666666666 24.96 24.9 3"
redis 127.0.0.1:6379> get richgauges.vmwprice
"72.08 72.04 72.08 72.02 3"