Loading…

Storing and Visualizing Time Series Data with InfluxDB and Universal Dashboard

InfluxDB is a time series database for storing and processing metrics and events. It’s open-source, cross-platform, has a small footprint and stellar performance when dealing with high throughput event data. In this blog post we will look at how to setup InfluxDB on Windows, send performance event data to the platform and build a dashboard to expose the data as easy to view charts using Universal Dashboard.

Installing InfluxDB

To install InfluxDB, you’ll need to visit their download page. There is a ZIP file that contains all the binaries necessary to run the database and execute commands against it. For the purpose of this blog post, I downloaded the 1.7.1 version found here: https://dl.influxdata.com/influxdb/releases/influxdb-1.7.1_windows_amd64.zip.

Once downloaded, I extracted the ZIP file to a folder. The binary list is shown below and clocks in right under 100 MB.

The InfluxDB database daemon is influxd.exe. To start the database, you need to run it from the command line with the -config flag and specify a config file. There is a default config file in the same directory.

influxd.exe -config ./influxdb.conf

You should see the executable start and begin listening for requests.

Configuring InfluxDB

To configure InfluxDB, you’ll need to create a database. The influx.exe command line tool can be used to connect to your database and execute commands. InfluxDB has some elements of SQL and it’s own query language.

The first step is to run influx.exe and create a database. This can be done with the CREATE DATABASE command. For the purpose of this example, I’ve created the performance_data database.

E:\influxdb>influx
Connected to http://localhost:8086 version 1.7.1
InfluxDB shell version: 1.7.1
Enter an InfluxQL query
> CREATE DATABASE performance_data
> SHOW DATABASES
name: databases
name
----
_internal
performance_data

Now that we have a database, we can begin to write data to it. You can write data directly from influx.exe but in this example, we will be using their REST API to populate the database with data from PowerShell.

Sending Data from PowerShell

The InfluxDB daemon exposes a REST API that listens on port 8086 by default. You can send data to the system with Invoke-RestMethod and the InfluxDB Line Protocol.

The syntax of the payload should follow this structure.

<measurement>[,<tag_key>=<tag_value>[,<tag_key>=<tag_value>]] <field_key>=<field_value>[,<field_key>=<field_value>] [<timestamp>]

The measurement is the “table” the particular data belongs to. A “tag” is an indexed value that identifies this measurement. It could be the host name of a machine or a performance counter name. A field is a non-indexed value of data. This is typically your event data. This could be your % of disk time usage or bytes per second in network reads.

Using Get-Counter we can collect data from a specified performance counter. We will then aggregate all instances of the counter values into a single value and send it to InfluxDB.

$InfluxUrl =  "http://localhost:8086/write?db=performance_data"
$Counter = '\Processor(_Total)\% Processor Time'

$Value = 0
(Get-Counter $Counter).CounterSamples | ForEach-Object {
    $Value += $_.CookedValue
}

Invoke-RestMethod -Method POST -Uri $InfluxUrl -Body "counter,host=$ENV:COMPUTERNAME,counter=$($Counter.Replace(' ', '\ ')) value=$value"

If the REST API doesn’t return an error, it worked. The tag and field values may require character escapes if they contain spaces or other special characters.

I’ve set tags for the host and the counter. If we pop back to influx.exe and query the database, you can see the counter values.

> USE performance_data
Using database performance_data
> SELECT * FROM counter
name: counter
time                counter                             host            value
----                -------                             ----            -----
1544065849105458300 \Processor(_Total)\% Processor Time DESKTOP-RB1QJB4 0.858510962407

The timestamp is automatically populated to Unix Epoch time in nanoseconds. You can optionally specify a time yourself. This is handy for grouping metrics together that happened around the same time and you don’t require nanosecond precision.

Querying Data from PowerShell

Now that we’ve populated our database with a metric, we can use the same REST API to query the values of these metrics. I’ve created a simple helper method to create a PowerShell-friendly hashtable around the InfluxDB JSON return values.

Get-InfluxDB queries the InfluxDB REST API and returns the value as a parsed hashtable. It also converts the time string into a .NET DateTime.

function Get-InfluxDB {
    param(
        [Parameter()]
        $Url = 'http://localhost:8086/query?db=performance_data',
        [Parameter()]
        $Query
    )

    $Results = Invoke-RestMethod -Uri "$Url&q=$Query"

    foreach($series in $results.results.series) {

        $ResultSeries = @{
            Fields = @()
        }

        foreach($tag in $series.tags.PSObject.Properties) {
            $ResultSeries[$tag.Name] = $Tag.Value
        }

        $Columns = $series.columns
        foreach($value in $series.values) {
            $Result = @{}
            for($i = 0; $i -lt $Columns.Length; $i++) {

                if ($Columns[$i] -eq 'time') {
                    $result.time = [DateTime]$value[$i]
                } else {
                    $Result[$columns[$i]] = $value[$i]
                }
            }

            $ResultSeries.fields += $result
        }

        $ResultSeries
    }
}

The result data contains the measurement, tags and fields return by the query. You can use the same query language that you used in influx.exe to query through the REST API. Invoking the query from our previous example from PowerShell looks like this.

PS C:\> ipmo C:\Users\adamr\Desktop\influxdb.psm1
PS C:\> Get-InfluxDb -Query 'SELECT * FROM counter'

Name                           Value
----                           -----
Fields                         {System.Collections.Hashtable}

PS C:\> $Data = Get-InfluxDb -Query 'SELECT * FROM counter'
PS C:\> $Data.Fields

Name                           Value
----                           -----
counter                        \Processor(_Total)\% Processor Time
time                           12/5/2018 8:10:49 PM
value                          0.858510962407
host                           DESKTOP-RB1QJB4

Now that we can access InfluxDB from PowerShell, let’s look at integrating it into Universal Dashboard.

Collecting Data with Universal Dashboard

Using the scheduled endpoint feature of Universal Dashboard, we can schedule an endpoint to run on an interval. Let’s run our collection endpoint every five seconds.

$Schedule = New-UDEndpointSchedule -Every 5 -Second
$Endpoint = New-UDEndpoint -Schedule $Schedule -Endpoint { }

Within the endpoint, let’s query some performance metric data and send it to InfluxDB. We use our own timestamp to ensure that all our metrics are stored with the same time value.

$InfluxUrl =  "http://localhost:8086/write?db=performance_data"
#Convert from millesecond to nanosecond
$TimeStamp = [DateTimeOffset]::Now.ToUnixTimeMilliseconds() * 1000000

$PerformanceStats = @(
    '\Processor(_Total)\% Processor Time'
    '\memory\% committed bytes in use'
    '\physicaldisk(_total)\% disk time'
)

foreach($PerformanceStat in $PerformanceStats) {
    $Value = 0
    (Get-Counter $PerformanceStat).CounterSamples | ForEach-Object {
        $Value += $_.CookedValue
    }

    Invoke-RestMethod -Method POST -Uri $InfluxUrl -Body "counter,host=$ENV:COMPUTERNAME,counter=$($PerformanceStat.Replace(' ', '\ ')) value=$value $TimeStamp"
}

In the above example, we are select three performance counters, query their current value and send that result into InfluxDB. You’ll be able to query the counter measurement to see your performance metrics.

Now that we have our data in InfluxDB, let’s create a chart to display it on our dashboard.

Display InfluxDB data in Universal Dashboard

The first step is to query InfluxDB for our data. Again, we can use Get-InfluxDB to retrieve data from our measurement. Let’s select all counters’ data that we received in the last five minutes and group by counter.

$Data = Get-InfluxDb -Query 'SELECT * FROM counter WHERE time > now() - 5m GROUP BY counter'

Now that we have our data, let’s transform it into a format that the Nivo Chart understands. The line chart requires hashtables with x and y values for each point in the chart. We can transform the InfluxDB data like this.

$ChartData = @()

foreach($series in $data) {

    $SeriesData = @{
        id =  $series.counter
        data = @()
    }

    foreach($field in $Series.Fields) {
        $SeriesData.data += @{
            x = $field.time
            y = $field.value
        }                        
    }

    $ChartData += $SeriesData
}

Now that the data is in the correct format, we can create our chart. We can set the bottom axis to rotate the labels 90 degrees, set some various styling parameters and provide the data.

$BottomAxis = New-UDNivoChartAxisOptions -TickRotation 90
New-UDNivoChart -Data $ChartData -Id "performanceStats" -Line -Responsive -MarginBottom 50 -MarginTop 50 -MarginRight 110 -MarginLeft 60 -YScaleMax 100 -YScaleMin 0 -EnableArea -AxisBottom $BottomAxis -Colors 'paired'

To ensure that the chart updates on a regular interval, we place the chart and data look up in an element that autorefreshs.

New-UDElement -Tag 'div' -Attributes @{ style = @{ "height" = '400px'}} -AutoRefresh -RefreshInterval 5 -Endpoint {
    # Chart code (don't worry the whole thing is linked at the bottom)
}

Now, we have a pretty chart that is displaying data from InfluxDB.

Conclusion

InfluxDB is really neat and really easy to integrate with PowerShell and Universal Dashboard. Storing your data persistently provides a much more useful tool than existing UDMonitors as page reloads do not affect the data that is shown in the chart.

For more information on InfluxDB, visit their documentation.

For a full example of the InfluxDB integration with Universal Dashboard, download this Gist and get up and running. You’ll need at least Universal Dashboard 2.2.0-beta2 and the (very) small InfluxDB PowerShell module I created.

The example includes the metrics I have shown in this post along with an example of a stream chart with network information.

Leave a Reply