Home » Posts tagged 'Query'
Tag Archives: Query
Show number of hours a computer has been sending heartbeats, per day
Today I needed a Kusto query to show number of heartbeat events per computer, per day, for the last week. The query also needed to estimate number of hours based on the amount of heartbeat events. The query is similar to the query in the Return data only during office hours and workdays post.
Heartbeat | where Computer == "ninja-linux" or Computer == "WORKSTATION13" | where TimeGenerated >= startofday(ago(7d)) | summarize minutes = count() by bin(TimeGenerated, 1d), Computer | project Date = format_datetime(TimeGenerated, 'dd-MM'), Computer, WeekDay = case( dayofweek(TimeGenerated) == "1:00:00:00", "Mo", dayofweek(TimeGenerated) == "2:00:00:00", "Tu", dayofweek(TimeGenerated) == "3:00:00:00", "We", dayofweek(TimeGenerated) == "4:00:00:00", "Th", dayofweek(TimeGenerated) == "5:00:00:00", "Fr", dayofweek(TimeGenerated) == "6:00:00:00", "Sa", dayofweek(TimeGenerated) == "0:00:00:00", "Su", "Unknown day"), Hours = minutes / 60, Events = minutes | order by Date
Custom availability monitoring
What if you need to monitor something that require a custom script? For example a sequence of checks? That is possible with a PowerShell script that do all the checks, and then submit the result to the workspace. In this example I will monitor port 25565 on a Minecraft server with a PowerShell script. Monitoring a network port is possible with the network insight feature, but it is still a good example as you can change the PowerShell script do do almost anything.
The first step was to create an Azure Automation runbook to check if the port is open. The runbook submit the result to Log Analytics through the data collector API.
A challenge with the runbook is schedules only allow it to run once per hour. To trigger the runbook more often, for example every five minutes, we can trigger it from a Logic Apps.
The PowerShell based runbook is now triggered to run every five minutes, sending its result to the Log Analytic workspace. Once the data is in the workspace, we can query it with a query, and for example show availability of the network port. As you can see on line six in the query, I have comment (for demo purpose) the line that shows only events from yesterday. The following blog post, Return data only during office hours and workdays , explains the query in details.
let totalevents = (24 * 12); Custom_Port_CL | extend localTimestamp = TimeGenerated + 2h | where Port_s == "Minecraft Port" | where Result_s == "Success" // | where localTimestamp between (startofday(now(-1d)) .. endofday(now(-1d)) ) | summarize sum01 = count() by Port_s | extend percentage = (todouble(sum01) * 100 / todouble(totalevents)) | project Port_s, percentage, events=sum01, possible_events=totalevents
The query will show percentage availability based on one event expected every five minutes.
Compare the current counter value with previous one
Today I received a question about comparing a performance counter value with the previous performance counter value. In the example, we look at free space on C and compare the current value with the previous. As there are few examples in the community, I thought this would be a good example to share.
Perf | where Computer == "idala" | where CounterName == "% Free Space" | where InstanceName == "C:" | serialize | extend prevValue = prev(CounterValue, 1) | extend diffvalue = CounterValue - prevValue | extend trend = case(CounterValue < prevValue, "Free Space Reduces", CounterValue > prevValue, "Free Space Increases", "No difference") | project TimeGenerated, InstanceName, CounterValue, prevValue, diffvalue, trend | order by TimeGenerated desc
First, we filter on a computer, counter name, and instance name. Before we can use Window functions on the result, we need to SERIALIZE it. SERIALIZE will freeze the result; in other words, freeze the order on the rows.
We use EXTEND to create a new column and assign it the value of the previous counterValue. “1” after CounterValue means we look on the 1 previous row; this is possible to do as we have a serialized set of rows.
We then use EXTEND to create a new column that will hold the difference (diffvalue) between the current counter value and the previous counter value.
Even if it is simple to see if the value has reduced or increased manually, we use CASE, and another EXTEND to write different text strings in a column depending on the current counter value and previous counter value.
Today I would like to quickly share two queries. The first query counts number of devices that sent a heartbeat last month. The second query shows the number of devices sent heartbeat per month, for the current year.
let LastMonthEndDate = (startofmonth(now()) - 1h); let LastMonthStartDate = startofmonth(LastMonthEndDate); Heartbeat | where TimeGenerated between(LastMonthStartDate .. (LastMonthEndDate)) | distinct Computer | summarize ['Devices Last Month'] = count()
let YearStartDate = (startofyear(now()) - 1h); Heartbeat | where TimeGenerated between(YearStartDate .. (now())) | extend Month = (datetime_part("month", TimeGenerated)) | summarize Devices = dcount(Computer) by Month