Collect and visualize custom data with Microsoft OMS Log Analytics

The OMS HTTP data collector allows you to collect any data from any source and send it over to OMS. Using the OMS view designer you can then visualize the data. Curious how this works? Read on!

Scenario “Tesla Supercharger”

You might know that I am a Tesla enthusiast and have done a lot on Tesla management with Microsoft products and solutions. No? Then check out this video.  So I decided to use a Tesla example for this as well. The goal is to bring Tesla Supercharger data to OMS and visualize it.

Step 1 – Collect the Data

First I need to collect the Tesla Supercharger data somewhere. The website supercharge.info has a full list of Tesla Superchargers that exist on the planet with all the needed details.

image

Using the URI http://supercharge.info/service/supercharge/allSites you get a JSON file with all the available data.

image

Now for this example I not only read the information, but convert it into a custom Powershell object, add another property – the fully concatenated address – and convert it back to a JSON file. Once the data is ready, we need 2 functions to prepare the connection and send the data to OMS. Here we go with the full script:

#OMS Data
$CustomerId = “YOUR OMS WORKSPACE ID”
$SharedKey = “YOUR OMS WORKSPACE SHARED KEY”
$LogType = “TeslaSuperchargerData” #Name of the Data Type in OMS
$TimeStampField = “”

#Get Supercharger data
$uri = “http://supercharge.info/service/supercharge/allSites”
$results = Invoke-WebRequest -Uri $uri -Method Get -UseBasicParsing
$results = $results | ConvertFrom-Json

#Prepare Supercharder data
$objects = @()

foreach($result in $results)
{
$fulladdress = $result[0].address.street + “, ” + $result[0].address.zip + ” ” + $result[0].address.city + “, ” + $result[0].address.country

$object = New-Object –TypeName PSObject
$object | Add-Member –MemberType NoteProperty –Name “Name” –Value $result.name
$object | Add-Member –MemberType NoteProperty –Name “Status” –Value $result.status
$object | Add-Member –MemberType NoteProperty –Name “DateOpened” –Value $result.dateOpened
$object | Add-Member –MemberType NoteProperty –Name “StallCount” –Value $result.stallCount
$object | Add-Member –MemberType NoteProperty –Name “Street” –Value $result.address.street
$object | Add-Member –MemberType NoteProperty –Name “ZIP” –Value $result.address.zip
$object | Add-Member –MemberType NoteProperty –Name “City” –Value $result.address.city
$object | Add-Member –MemberType NoteProperty –Name “Country” –Value $result.address.country
$object | Add-Member –MemberType NoteProperty –Name “FullAddress” –Value $fulladdress
$objects += $object

}

$json = $objects | convertto-json

# Create the function to create the authorization signature
Function Build-Signature ($customerId, $sharedKey, $date, $contentLength, $method, $contentType, $resource)
{
$xHeaders = “x-ms-date:” + $date
$stringToHash = $method + “`n” + $contentLength + “`n” + $contentType + “`n” + $xHeaders + “`n” + $resource

$bytesToHash = [Text.Encoding]::UTF8.GetBytes($stringToHash)
$keyBytes = [Convert]::FromBase64String($sharedKey)

$sha256 = New-Object System.Security.Cryptography.HMACSHA256
$sha256.Key = $keyBytes
$calculatedHash = $sha256.ComputeHash($bytesToHash)
$encodedHash = [Convert]::ToBase64String($calculatedHash)
$authorization = ‘SharedKey {0}:{1}’ -f $customerId,$encodedHash
return $authorization
}

# Create the function to create and post the request
Function Post-OMSData($customerId, $sharedKey, $body, $logType)
{
$method = “POST”
$contentType = “application/json”
$resource = “/api/logs”
$rfc1123date = [DateTime]::UtcNow.ToString(“r”)
$contentLength = $body.Length
$signature = Build-Signature `
-customerId $customerId `
-sharedKey $sharedKey `
-date $rfc1123date `
-contentLength $contentLength `
-fileName $fileName `
-method $method `
-contentType $contentType `
-resource $resource
$uri = “https://” + $customerId + “.ods.opinsights.azure.com” + $resource + “?api-version=2016-04-01”

$headers = @{
“Authorization” = $signature;
“Log-Type” = $logType;
“x-ms-date” = $rfc1123date;
“time-generated-field” = $TimeStampField;
}

$response = Invoke-WebRequest -Uri $uri -Method $method -ContentType $contentType -Headers $headers -Body $body -UseBasicParsing
return $response.StatusCode

}

# Submit the data to the API endpoint
Post-OMSData -customerId $customerId -sharedKey $sharedKey -body $json -logType $logType

Once you execute the query, give OMS some minutes until the data gets displayed in log analytics. However, it takes several hours until you will see all the properties of the new data type as well as their values! Once the data is fully available, you can use the search options available to work with the collected data. Remember that OMS adds a suffix to all your custom data types and properties. More information about the injection process and custom data is available here.

image

Step 2 – Visualization with a view

Now as the data is available in OMS lets create a view to visualize it with the view designer. In the overview you should see the view designer. If this is not the case you might need to enable it under configuration\preview features.

image

Now give the new tile a name and use a query for the donut. In my case this is

* | measure countdistinct(Name_s) by Country_s

to group all available superchargers by country.

image

Now switch over to the view configuration and add the view types needed. In my case I wanted to display the Tesla Superchargers in my country and display the stall count. Plus I wanted to have a second view with Superchargers that are planned or already under construction.

image

View 1

TITLE

* Country_s=Switzerland Status_s=OPEN | measure countdistinct(Name_s) by Name_s

LIST

Type=TeslaSuperchargerData_CL Country_s=Switzerland Status_s=OPEN | measure max(StallCount_d) by Name_s

View 2

TITLE

* Country_s=Switzerland (Status_s=CONSTRUCTION or Status_s=PERMIT) | measure countdistinct(Name_s) by Name_s

LIST

Type=TeslaSuperchargerData_CL Country_s=Switzerland (Status_s=CONSTRUCTION or Status_s=PERMIT) | measure max(StallCount_d) by Name_s

The result looks something like this:

image

image

Step 3 – Update the Tesla Supercharger data

Now, Tesla is heavily investing in their Supercharger infrastructure, which means that data will change constantly. So how can we make sure that we have the current data available in OMS at all time? One way to go is to use log analytic alerts together with Azure Automation.

image

In the alert configuration I use the query to get out all Tesla Supercharger data that’s available in OMS. I use a time window of 24 hours and check it every 60 minutes. That means that every hour the system will check if there is Tesla Supercharger data in OMS that is older than 24 hours. If this is the case, I trigger a runbook that lives in my connected Azure Automation account. The runbook is based on the exact same script that I showed in step 1.

image

image

image

Conslusion

The HTTP data collector together with the view designer is a powerful way to collect and analyze data from everywhere in a super flexible way. But wait, it gets even better: In the next blog post I will demonstrate how to forward this data to PowerBI to create powerful reports that you can share with your pals!

Update: Check out part 2 here!

Cheers
Marcel

About Marcel Zehner

Microsoft Azure MVP
This entry was posted in Azure and tagged , , , , , , . Bookmark the permalink.

4 Responses to Collect and visualize custom data with Microsoft OMS Log Analytics

  1. Pingback: Visualize OMS Log Analytics data with PowerBI | marcelzehner.ch

  2. Hi Marcel,

    This is awesome & a very clear post outlining some pretty heavy concepts. I’ll be running this through my own lab on another datasource really soon 🙂

    Damian

  3. Pingback: OMS View Designer – Use Name & Value Separator | marcelzehner.ch

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s