Passing column name as parameter in Kusto query - azure

I need to pass the column name dynamically into the query. While following is syntactically correct it does not really execute the condition on the particular column.
Is this even possible in Kusto?
let foo = (duration: timespan, column:string) {
SigninLogs
| where TimeGenerated >= ago(duration)
| summarize totalPerCol = count() by ['column']
};
//foo('requests')<-- does not work
//foo('user') <-- does not work
//foo('ip')<-- does not work

you can try using the column_ifexists() function: https://learn.microsoft.com/en-us/azure/data-explorer/kusto/query/columnifexists.
for example:
let foo = (column_name:string) {
datatable(col_a:string)["hello","world"]
| summarize totalPerCol = count() by column_ifexists(column_name, "")
};
foo('col_a')
col_a
totalPerCol
hello
1
world
1

Related

How to use result of first KQL query in the second query to filter results?

I have a first KQL query that returns a list of domain names, and then I want to use these to filter another KQL query. I just can't figure out the syntax to do it. Is there a way to use the contains() operator with a for loop/iteration in KQL?
KQL - Query 1
let hostnames = () {
AllDomains
| where hostname !contains "default.com" and hostname != ""
| distinct hostname
}
KQL - Query 2
let start_date = ago(10m);
let end_date = now();
LogEvents
| where env_time between (start_date .. end_date)
| where headers contains "X-Forwarded-For"
| where queryString contains (hostnames()) //This is what is needed to filter on all the domains from first query.
| project queryString
this could work:
let hostnames =
AllDomains
| where isnotempty(hostname) and hostname !has "default.com"
| distinct hostname
;
let start_date = ago(10m);
let end_date = now();
LogEvents
| where env_time between (start_date .. end_date)
| where headers contains "X-Forwarded-For"
| where queryString has_any (hostnames)
| project queryString
It would be better if you'll provide a sample of how your data looks and what you are trying to accomplish, but I think that instead of contains you'd want to use has_any

Passing Query Result to a function as a parameter Kusto

I want to create a function that allows me to pass the tabular result of a query as a parameter without specifying the table column names.
This is what I want as a result:
let Func = (T) {
T
| where Source has_any ("value")
};
let EventVar = Event | where TimeGenerated > ago(30d);
Func (EventVar);
You do not need to specify all columns in the tabular parameter schema, only those columns that you need to use inside the function.
For example, this is how your query can look like:
let CustomFunc = (T:(Source:string)) {
T | where Source has_any ("value")
};
let EventVar = Event | where TimeGenerated > ago(30d);
CustomFunc(EventVar);
The query above will output all columns from the table EventVar if its rows match the condition in your function. The only requirement is that the table EventVar has a column of type string with name Source, and it can have any number of other columns.
It is also possible to accept any tabular schema by defining the input tabular parameter like T:(*), but in this case you will not be able to reference any column names inside the function. See example 4 on the documentation page for reference.

KQL: How to parse a log and pull proper substrings? [duplicate]

I have a table that consists of one row and number of columns. One of the columns is named EventProperties which is a JSON of properties of this format:
{
"Success":true,
"Counters":{
"Counter1":1,
"Counter2":-1,
"Counter3":5,
"Counter4":4,
}
}
I want to convert the Counters from this JSON to a two-column table of keys and values, where the first column is the name of the counter (e.g. Counter3) and the second column is the value of the counter (e.g. 5).
I've tried this:
let eventPropertiesCell = materialize(MyTable
| project EventProperties
);
let countersStr = extractjson("$.Counters", tostring(toscalar(eventPropertiesCell)), typeof(string));
let countersJson = parse_json(countersStr);
let result =
print mydynamicvalue = todynamic(countersJson)
| mvexpand mydynamicvalue
| evaluate bag_unpack(mydynamicvalue);
result
But I get a table with a column for each counter from the JSON, and number of rows that is equal to the number of counters, while only one random row is filled with the counter value. For example, with the JSON from the example above, I get:
But I want something like this:
Any help will be appreciated!
you could try using mv-apply as follows:
datatable(event_properties:dynamic)
[
dynamic({
"Success":true,
"Counters":{
"Counter1":1,
"Counter2":-1,
"Counter3":5,
"Counter4":4
}
}),
dynamic({
"Success":false,
"Counters":{
"Counter1":1,
"Counter2":2,
"Counter3":3,
"Counter4":4
}
})
]
| mv-apply event_properties.Counters on (
extend key = tostring(bag_keys(event_properties_Counters)[0])
| project key, value = event_properties_Counters[key]
)
| project-away event_properties

Custom aggregate function on summarize

I want to calculate a statistic mode on a column during summarization of a table.
My CalculateMode function that I try is like this:
.create function CalculateMode(Action:int, Asset:string, Start:long, End:long) {
Event
| where Time between (Start .. End) and IdAction == Action and IdDevice == Device
| summarize Count = countif(isnotnull(Result) and isnotempty(Result)) by tostring(Result)
| top 1 by Count desc
| project ActionResult
}
OR
.create function CalculateMode(T:(data:dynamic)) {
T
| summarize Count = countif(isnotnull(data) and isnotempty(data)) by tostring(data)
| top 1 by Count desc
| project data
}
when i using first coding on summarizing:
Event
| summarize Result = CalculateMode(toint(IdAction), tostring(IdDevice), Start, End) by Category
Obtain this error No tabular expression statement found and
when i using second coding on summarizing:
Event
| summarize Result = CalculateMode(Result) by Category
I get this error
CalculateMode(): argument #1 must be a tabular expression
What can I do? Where am I doing something wrong?
Thanks
You can't just do summarize Result = CalculateMode(Result). You have to decide which aggregation function you want to summarize by (see the full list of aggregation functions here).

Get the name of a month in Application Insights

I am new to application insights and I am writing a query to pull few data from Azure. I need to fetch the name of the month. I tried the below query, but I am getting just the numeric value of 1 in output.
I need the value as string in a separate column like "January", "February". Below is the output snap:
Query I wrote:
customEvents | summarize Count = dcount(cloud_RoleInstance) by ProductVersion = tostring(customDimensions.["Version"]), Month = monthofyear(timestamp)
Any suggestion would be highly helpful. Thanks.
There is no built-in function for this. So you should define a user-defined function to achieve this.
The sample code like below, and you can modify it to meet your need:
let f=(a:int){
case(a==1,"Jan",
a==2,"Feb",
a==3,"Mar",
//add the other month
a==12,"Dec",
"Error"
)
};
traces
| summarize count() by cloud_RoleName ,Month=f(getmonth(timestamp))
The test result:
And here is the query just for your case, please add other month in the function.
let f=(a:int){
case(a==1,"Jan",
a==2,"Feb",
a==3,"Mar",
//add the other month
a==12,"Dec",
"Error"
)
};
customEvents
| summarize Count = dcount(cloud_RoleInstance) by ProductVersion = tostring(customDimensions.["Version"]), Month = f(getmonth(timestamp))

Resources