Kusto 按月制作系列

Kusto make-series by month

我真的很难弄清楚如何使用 Kusto make-series 函数但按月输出结果。下面的当前示例设置为 1d(即 1 天)。

我知道月份和年份不是时间跨度的有效运算符,因此正在寻找解决方法。

let startDateTime = datetime(2022-04-13T08:25:51.000Z);
let endDateTime = datetime(2022-04-19T21:25:51.876Z);
let m = materialize(traces | where timestamp > startDateTime and timestamp < endDateTime
| extend Message=parse_json(message)
| extend LogLevel = Message.LogLevel,
LogEventCategory = Message.LogEventCategory,
LogEventType = Message.LogEventType,
LogEventSource = Message.LogEventSource,
LogData = Message.LogData,
LogUserId = Message.LogUserId,
LogUsername = Message.LogUsername,
LogForename = Message.LogForename,
LogSurname = Message.LogSurname,
LogCountry = Message.LogCountry,
LogRegionName = Message.LogRegionName,
LogCity = Message.LogCity,
LogZip = Message.LogZip,
LogLatitude = Message.LogLatitude,
LogLongitude = Message.LogLongitude,
LogIsp = Message.LogIsp,
LogIpAddress = Message.LogIpAddress,
LogMobile = Message.LogMobile);
m | where Message.LogLevel == 'Information' | where Message.LogEventCategory == 'WebApp-CLIENT'
| make-series counter=count() default=0 on timestamp in range(startDateTime, endDateTime, 1d); // Need to define 1month, NOT 1d

您可以使用 summarize 运算符代替 make-series 吗?这样您就可以按 startofmonth(datetime_column_name)

进行计数

例如:

click to run

range dt from ago(365d) to now() step 1d
| extend month = startofmonth(dt)
// the following line skips a few months, for the purpose of the example
| where month !in(datetime(2022-03-01), datetime(2022-01-01), datetime(2021-10-01), datetime(2021-09-01), datetime(2021-08-01))
| summarize count() by month
| render columnchart

或者,如果这不符合您的情况 - 您可以创建日期时间列的最小值和最大值之间的所有月份的列表,并在该列表与上面的汇总之间执行外部联接

例如(输出与上图完全相同的柱形图):

let T = range dt from ago(365d) to now() step 1d;
let min_max = toscalar(T | summarize pack_array(min(dt), max(dt)));
let min = todatetime(min_max[0]);
let max = todatetime(min_max[1]);
T
| extend month = startofmonth(dt)
// the following line skips a few months, for the purpose of the example
| where month !in(datetime(2022-03-01), datetime(2022-01-01), datetime(2021-10-01), datetime(2021-09-01), datetime(2021-08-01))
| summarize count() by month
| join kind = rightouter (
    range dt from min to max step 20d
    | summarize by month = startofmonth(dt)
) on month
| project month = coalesce(month, month1), count_ = coalesce(count_, 0)
| render columnchart  

我刚刚意识到还有一个额外的方法。

  1. 使用 1d 的步骤创建 make-series,但对于 on 子句,而不是使用 dt(我的示例中的日期时间字段) 使用 startofmonth(dt).

    这与在“标准”make-series -
    之前添加 | extend dt = startofmonth(dt) 具有相同的效果 数据汇总将在每个月的 1 日完成,每隔一天将没有数据(见底部图像)。

  2. 使用 mv-apply 从系列中过滤除每月 1 日以外的所有日期。

    理论上我们可以跳过 make_list 的使用,让系列展开,但是我们需要做一些其他操作,包括在渲染运算符中定义 xcolumn


// Generation of a data sample. Not part of the solution.
let t = materialize(range i from 1 to 1000 step 1 | extend dt = ago(365d*rand()) | where getmonth(dt) !in (3,6,9,10,11));
// The solution starts here.
t
| make-series count() on dt = startofmonth(dt) step 1d
| mv-apply count_, dt to typeof(datetime) on (where dt == startofmonth(dt) | summarize make_list(count_), make_list(dt))
| render timechart 

Fiddle


这是没有 mv-apply 部分的样子(在不同的随机数据样本上)。
请注意,所有数据都是在每个月的第一天汇总的。

我已经接受了这个问题的答案,但后来想出了另一种选择,我已经按照以下时间间隔进行了测试:

年初 月初 周开始 开始日

只是一个旁注,startofweek assmes Sunday with int value,根据下面评论的一些反馈,我用 'startofweek(s-1d)+1d' 更新了代码,下面的例子用注释掉的注释反映了这一点,所以你可以看到我把它放在哪里:

let startDateTime = datetime(2022-01-1T08:00:00.000Z);
let endDateTime = datetime(2022-04-21T08:00:00.000Z);
let m = materialize(traces | where timestamp > startDateTime and timestamp < endDateTime
| extend Message=parse_json(message)
| extend LogLevel = Message.LogLevel,
LogEventCategory = Message.LogEventCategory,
LogEventType = Message.LogEventType,
LogEventSource = Message.LogEventSource,
LogData = Message.LogData,
LogUserId = Message.LogUserId,
LogUsername = Message.LogUsername,
LogForename = Message.LogForename,
LogSurname = Message.LogSurname,
LogCountry = Message.LogCountry,
LogRegionName = Message.LogRegionName,
LogCity = Message.LogCity,
LogZip = Message.LogZip,
LogLatitude = Message.LogLatitude,
LogLongitude = Message.LogLongitude,
LogIsp = Message.LogIsp,
LogIpAddress = Message.LogIpAddress,
LogMobile = Message.LogMobile);
m | where Message.LogLevel == 'Information' | where Message.LogEventCategory == 'WebApp-CLIENT'
| summarize Count=count() by timestamp=startofweek(timestamp-1d)+1d // so week starts on Monday
| join kind=rightouter (
        range s from startDateTime to endDateTime step 1d 
        | summarize by timestamp = startofweek(s-1d)+1d // so week starts on Monday
    ) on timestamp
    | project timestamp=coalesce(timestamp, timestamp1), Count = coalesce(Count, 0)

下一个使用 startofmonth 的例子

let startDateTime = datetime(2022-03-20T20:00:00.000Z);
let endDateTime = datetime(2022-04-20T21:00:00.000Z);
let m = materialize(traces | where timestamp > startDateTime and timestamp < endDateTime
| extend Message=parse_json(message)
| extend LogLevel = Message.LogLevel,
LogEventCategory = Message.LogEventCategory,
LogEventType = Message.LogEventType,
LogEventSource = Message.LogEventSource,
LogData = Message.LogData,
LogUserId = Message.LogUserId,
LogUsername = Message.LogUsername,
LogForename = Message.LogForename,
LogSurname = Message.LogSurname,
LogCountry = Message.LogCountry,
LogRegionName = Message.LogRegionName,
LogCity = Message.LogCity,
LogZip = Message.LogZip,
LogLatitude = Message.LogLatitude,
LogLongitude = Message.LogLongitude,
LogIsp = Message.LogIsp,
LogIpAddress = Message.LogIpAddress,
LogMobile = Message.LogMobile);
m | where Message.LogLevel == 'Information' | where Message.LogEventCategory == 'WebApp-CLIENT'
| summarize Count=count() by timestamp=startofmonth(timestamp)
| join kind=rightouter (
        range s from startDateTime to endDateTime step 1d 
        | summarize by timestamp = startofmonth(s)
    ) on timestamp
    | project timestamp=coalesce(timestamp, timestamp1), Count = coalesce(Count, 0)

从其他人的帮助和回答来看,似乎有各种不同的方式来回答这个问题。我并不是以任何方式声称自己是专家,并且可能有更好的解决方案,但从我自己上面的测试来看,我现在似乎得到了想要的结果。感谢大家的意见。