Is there a way to project literal value of severityLevel in Application Insights query?
Consider following query:
union
customEvents,
dependencies,
exceptions,
performanceCounters,
traces
| order by timestamp desc
| project timestamp, operation_Name, itemType, severityLevel, message = strcat(name, message, outerMessage), customDimensions, ['details']
In the output, severityLevel value is numeric, I want the equivalent descriptive value in according with SeverityLevel Enum definition
I am able to get the severityLevel descriptive value.
Use the below query snippet
union
customEvents,
dependencies,
exceptions,
performanceCounters,
traces
| order by timestamp desc
| project timestamp, operation_Name, itemType, severityLevel, message = strcat(name, message, outerMessage), customDimensions, ['details']
| extend severityLevel = case(severityLevel == 0, "Verbose",
severityLevel == 1, "Information",
severityLevel == 2, "Warning",
severityLevel == 3, "Error",
severityLevel == 4, "Critical",
"-")
Related
In App Insight, how can I write a KQL that save a query result into a variable, and use that variable later in a second query?
For example, find the timestamp when an incident happens:
let incidentTime = traces
| where message = "UNIQUE IDENTIFIER"
| limit 1
Later use this timestamp in a 2nd query to find nearby traces when incident happens
traces
| where timestamp between (datetime_diff('minute', -1, incidentTime)..incidentTime)
The second query gives me an error basically saying cannot retrieve the scalar value from incidentTime.
How can I read the value from incidentTime and put it into the 2nd query?
you can use toscalar() and around():
https://learn.microsoft.com/en-us/azure/data-explorer/kusto/query/toscalarfunction
https://learn.microsoft.com/en-us/azure/data-explorer/kusto/query/around-function
for example:
let incidentTime = toscalar(
traces
| where message = "UNIQUE IDENTIFIER"
| project timestamp
| limit 1
);
traces
| where around(timestamp, incidentTime, 1m)
similarly, if you want to do so for multiple columns:
let params = toscalar(
traces
| where message = "UNIQUE IDENTIFIER"
| project pack_array(timestamp, username)
| limit 1
);
traces
| where around(timestamp, todatetime(params[0]), 1m)
| where username == tostring(params[1])
I have this query that almost works:
datatable (timestamp:datetime, value:dynamic)
[
datetime("2021-04-19"), "a",
datetime("2021-04-19"), "b",
datetime("2021-04-20"), 1,
datetime("2021-04-20"), 2,
datetime("2021-04-21"), "b",
datetime("2021-04-22"), 2,
datetime("2021-04-22"), 3,
]
| project timestamp, stringvalue=iif(gettype(value)=="string", tostring(value), ""), numericvalue=iif(gettype(value)=="long", toint(value), int(null))
| summarize any(stringvalue), avg(numericvalue) by bin(timestamp, 1d)
| project timestamp, value=iif(isnan(avg_numericvalue), any_stringvalue, avg_numericvalue)
This splits the values in the value field into stringvalue if the value is string and numericvalue of the value is long. Then it summarizes the values based on day level, for the string values it just takes any value and for the numeric values is calculates the average.
After this I want to put the values back into the value field.
I was thinking that the last row could be like below but the dynamic function only wants literals
| project timestamp, value=iif(isnan(avg_numericvalue), dynamic(any_stringvalue), dynamic(avg_numericvalue))
If I do it like this it will actually work:
| project timestamp, value=iif(isnan(avg_numericvalue), parse_json(any_stringvalue), parse_json(tostring(avg_numericvalue)))
But is there a better way than converting it to json and back?
iff expects the type of the 2nd and 3rd arguments to match. In your case, one is a number, and the other one is a string. To fix the issue, just add tostring() around the number:
datatable (timestamp:datetime, value:dynamic)
[
datetime("2021-04-19"), "a",
datetime("2021-04-19"), "b",
datetime("2021-04-20"), 1,
datetime("2021-04-20"), 2,
datetime("2021-04-21"), "b",
datetime("2021-04-22"), 2,
datetime("2021-04-22"), 3,
]
| project timestamp, stringvalue=iif(gettype(value)=="string", tostring(value), ""), numericvalue=iif(gettype(value)=="long", toint(value), int(null))
| summarize any(stringvalue), avg(numericvalue) by bin(timestamp, 1d)
| project timestamp, value=iif(isnan(avg_numericvalue), any_stringvalue, tostring(avg_numericvalue))
I am trying to achieve these things:
Get most recent data for certain fields (base on timestamp) -> call this latestRequest
Get previous data for these fields (basically timestamp < latestRequest.timestamp)-> call this previousRequest
Count the difference between latestRequest and previousRequest
This is what I come with now:
let LatestRequest=requests
| where operation_Name == "SearchServiceFieldMonitor"
| extend Mismatch = split(tostring(customDimensions.IndexerMismatch), " in ")
| extend difference = toint(Mismatch[0])
, field = tostring(Mismatch[1])
, indexer = tostring(Mismatch[2])
, index = tostring(Mismatch[3])
, service = tostring(Mismatch[4])
| summarize MaxTime=todatetime(max(timestamp)) by service,index,indexer;
let previousRequest = requests
| where operation_Name == "SearchServiceFieldMonitor"
| extend Mismatch = split(tostring(customDimensions.IndexerMismatch), " in ")
| extend difference = toint(Mismatch[0])
, field = tostring(Mismatch[1])
, indexer = tostring(Mismatch[2])
, index = tostring(Mismatch[3])
, service = tostring(Mismatch[4])
|join (LatestRequest) on indexer, index,service
|where timestamp <LatestRequest.MaxTime
However, I get this error from this query:
Ensure that expression: LatestRequest.MaxTime is indeed a simple name
I tried to use toDateTime(LatestRequest.MaxTime) but it doesn't make any difference. What I am doing wrong?
The error you get is because you can't refer to a column in a table using the dot notation, you should simply use the column name since the results of a join operator is a table with the applicable columns from both side of the join.
An alternative to join might be using the row_number() and prev() functions. You can find the last record and the one before it by ordering the rows based on the key and timestamp and then calculate the values between the current row and the row before it.
Here is an example:
datatable(timestamp:datetime, requestId:int, val:int)
[datetime(2021-02-20 10:00), 1, 5,
datetime(2021-02-20 11:00), 1, 6,
datetime(2021-02-20 12:00), 1, 8,
datetime(2021-02-20 10:00), 2, 10,
datetime(2021-02-20 11:00), 2, 20,
datetime(2021-02-20 12:00), 2, 30,
datetime(2021-02-20 13:00), 2, 40,
datetime(2021-02-20 13:00), 3, 100
]
| order by requestId asc, timestamp desc
| extend rn = row_number(0, requestId !=prev(requestId))
| where rn <= 1
| order by requestId, rn desc
| extend diff = iif(prev(rn) == 1, val - prev(val), val)
| where rn == 0
| project-away rn
The results are:
I have the following user-defined functions with the intention of using a case conditional to output a table of 0s or 1s saying whether or not an account is active.
case needs scalar values as it's arguments, ie pro_account_active(account) and basic_account_active(account) need to be scalar values.
I'm struggling to get around the limitation of toscalar:
User-defined functions can't pass into toscalar() invocation
information that depends on the row-context in which the function is
called.
I think if there was a function I can use in place of the "??????" that would convert active to a scalar and return it from the function it would work.
Any help greatly appreciated
let basic_account_active=(account:string) {
basic_check_1(account) // returns 0 or 1 row only
| union basic_check_2(account)
| summarize result_count = count()
| extend active = iff(result_count == 2, 1, 0)
| ??????
};
let pro_account_active=(account:string) {
pro_check_1(account) // returns 0 or 1 row only
| union pro_check_2(account)
| summarize result_count = count()
| extend active = iff(result_count == 2, 1, 0)
| ??????
};
let is_active=(account_type:string, account:string) {
case(
account_type == 'pro', pro_account_active(account),
account_type == 'basic', basic_account_active(account),
-1
)
};
datatable(account_type:string, account:string)
[
'pro', '89e5678a92',
'basic', '9d8263da45',
'pro', '0b975f2454a',
'basic', '112a3f4753',
]
| extend result = is_active(account_type, account)
You can convert the output of a query to a scalar by using the toscalar() function, i.e.
let basic_account_active=(account:string) {
toscalar(basic_check_1(account) // returns 0 or 1 row only
| union basic_check_2(account)
| summarize result_count = count()
| extend active = iff(result_count == 2, 1, 0))};
From your example it looks that you have two tables per each account type and if both have entrees for a specific account, then the account is considered active. Is that correct? If so, I would use the "join" operator to find all the entrees in the applicable tables and count them. Here is an example of one way to do it (there are other ways as well).
let basicAccounts1 = datatable(account_type:string, account:string)[ 'basic', '9d8263da45', 'basic', '111111'];
let basicAccounts2 = datatable(account_type:string, account:string)[ 'basic', '9d8263da45', 'basic', '222222'];
let proAccounts1 = datatable(account_type:string, account:string)[ 'pro', '89e5678a92', 'pro', '111111'];
let proAccounts2 = datatable(account_type:string, account:string)[ 'pro', '89e5678a92', 'pro', '222222'];
let AllAccounts = union basicAccounts1, basicAccounts2, proAccounts1, proAccounts2
| summarize count() by account, account_type;
datatable(account_type:string, account:string)
[
'pro', '89e5678a92',
'basic', '9d8263da45',
'pro', '0b975f2454a',
'basic', '112a3f4753',
]
| join kind=leftouter hint.strategy=broadcast (AllAccounts) on account, account_type
| extend IsActive = count_ >=2
| project-away count_, account1, account_type1
The results are:
is it possible to get the query to summarize from multiple Application insights? I cant get it working with Union command.
Example query:
union
app("applicationinsight02").requests,
app("applicationinsight03").requests
availabilityResults
| where timestamp > ago(30d)
// check whether location failed within 5m bin
| summarize _failure=iff(countif(success == 0)>0, 1, 0) by name, location, bin(timestamp, 5m)
// check whether all locations failed within 5m bin
| summarize _failureAll=iff(sum(_failure)>=3, 1, 0) by name, bin(timestamp, 5m)
// count all failed 5 minute bins and total number of bins
| summarize _failuresCount=sum(_failureAll), _totalCount=count() by name
| project ["Name"] = name, ["SLA"] = todouble(_totalCount - _failuresCount) / todouble(_totalCount) * 100
| order by ["SLA"]
Yes, something like so
union
app("application-insights-01").requests,
app("application-insights-02").requests
| where timestamp > ago(1h)
| summarize sum(itemCount) by appName, bin(timestamp, 5m)
That will summarize the requests and show you the split by appname (the app insights resource name). Amend the where clause to fit your requirements
An example for availability results with your query would look like so, just replace application-insights-01/02 with your instance names
union
app("application-insights-01").availabilityResults,
app("application-insights-02").availabilityResults
| where timestamp > ago(1h)
| summarize _failure=iff(countif(success == 0)>0, 1, 0) by name, location, bin(timestamp, 5m)
| summarize _failureAll=iff(sum(_failure)>=3, 1, 0) by name, bin(timestamp, 5m)
| summarize _failuresCount=sum(_failureAll), _totalCount=count() by name
| project ["Name"] = name, ["SLA"] = todouble(_totalCount - _failuresCount) / todouble(_totalCount) * 100
| order by ["SLA"]