SynapseMLLogs
| where TIMESTAMP > ago(30d)
| where TelemetryApplicationInfo has "ChatMagics"
| where Message has "Telemetry: command="
| extend Command = extract(strcat(@"Telemetry: command=", @"(\w+)"), 1, tostring(Message))
| where isnotempty(Command)
| extend IsRunner = (Tenant == "A365BBCRunner")
| extend AppInfo = parse_json(TelemetryApplicationInfo)
| summarize
Invocations = count(),
Runner = countif(IsRunner),
RealUser = countif(not(IsRunner)),
UniqueWorkspaces = dcount(Workspace),
UniqueArtifacts = dcount(tostring(AppInfo.ArtifactId)),
Versions = make_set(tostring(AppInfo.ApplicationVersion), 5)
by Command
| extend PctRunner = round(100.0 * Runner / Invocations, 1)
| order by Invocations desc
SynapseMLLogs
| where TIMESTAMP > ago(90d)
| where TelemetryApplicationInfo has "ChatMagics"
| where Message has "Telemetry: command="
| extend Command = extract(strcat(@"Telemetry: command=", @"(\w+)"), 1, tostring(Message))
| where isnotempty(Command)
| summarize Invocations = count(),
FirstSeen = min(TIMESTAMP),
LastSeen = max(TIMESTAMP)
by Command
| order by Invocations desc
SynapseMLLogs | where TIMESTAMP > ago(30d) | where TelemetryApplicationInfo has "ChatMagics" | where Message has "Telemetry: command=" | extend Command = extract(strcat(@"Telemetry: command=", @"(\w+)"), 1, tostring(Message)) | where isnotempty(Command) | summarize Count = count() by Day = startofday(TIMESTAMP), Command | order by Day asc, Count desc | render columnchart with (kind=stacked, xcolumn=Day, ycolumns=Count, series=Command)
// Probe — most-recent 20 raw command rows
SynapseMLLogs
| where TIMESTAMP > ago(1d)
| where TelemetryApplicationInfo has "ChatMagics"
| where Message has "Telemetry: command="
| extend AppInfo = parse_json(TelemetryApplicationInfo)
| project TIMESTAMP,
Workspace,
ArtifactId = tostring(AppInfo.ArtifactId),
ArtifactType = tostring(AppInfo.ArtifactType),
AppVersion = tostring(AppInfo.ApplicationVersion),
Command = extract(strcat(@"Telemetry: command=", @"(\w+)"), 1, tostring(Message)),
Message
| order by TIMESTAMP desc
| take 20
SynapseMLLogs | where TIMESTAMP > ago(7d) | where TelemetryApplicationInfo has "ChatMagics" | extend EventName = extract(@"Telemetry:\s*(\w+)=", 1, tostring(Message)) | where isnotempty(EventName) | summarize Count = count(), Sample = take_any(Message) by EventName | order by Count desc
Every ChatMagics telemetry event in this Kusto endpoint over the last 90 days — 188,800 events across 11 commands — carries Tenant = A365BBCRunner. That tenant is Microsoft's internal BBC (Build/VHD validation) CI runner, used to validate Spark/Fabric VHD images before release. The chat-magics package is shipped into those VHDs via the ADO feed BBC-VHD_PublicPackages (see .pipelines/chat-magics-Official.yml:19) and validated by re-running test notebooks against each new VHD build.
| Tenant | EnvironmentType | Events | Share |
|---|---|---|---|
| A365BBCRunner | TRIPROD | 180,524 | 95.6% |
| A365BBCRunner | PROD | 4,668 | 2.5% |
| A365BBCRunner | TriPROD | 3,608 | 1.9% |
| (any other tenant) | 0 | 0.00% | |
| Command | Runner events | Runner notebooks | Real-user events | Real-user notebooks | % Runner |
|---|
A single raw row from the table reveals the CI stack:
.pipelines/chat-magics-Official.yml:19 — ADO_FEEDS: "chat-magics-fabric,BBC-VHD_PublicPackages" ADO
BBC-VHD pulls the chat-magics package from this feed, bakes it into Spark/Fabric runtime VHD images, then runs validation notebooks (e.g. tests/magics/DataSummaries.ipynb) on each new VHD build. That validation suite is what produces all the telemetry visible here.
// 1) All distinct Tenants emitting ChatMagics (90 d) — only A365BBCRunner shows up
SynapseMLLogs
| where TIMESTAMP between (datetime(2026-02-11) .. datetime(2026-05-12))
| where TelemetryApplicationInfo has "ChatMagics"
| where Message has "Telemetry: command="
| summarize Count = count() by Tenant, EnvironmentType
| order by Count desc
// 2) Per-command runner-vs-real-user split (90 d)
SynapseMLLogs
| where TIMESTAMP between (datetime(2026-02-11) .. datetime(2026-05-12))
| where TelemetryApplicationInfo has "ChatMagics"
| where Message has "Telemetry: command="
| extend Command = extract(@"Telemetry: command=(\w+)", 1, Message)
| extend IsRunner = (Tenant == "A365BBCRunner")
| summarize Total = count(),
Runner = countif(IsRunner),
RealUser = countif(not(IsRunner)),
RunnerArt = dcountif(tostring(parse_json(TelemetryApplicationInfo).ArtifactId), IsRunner),
RealArt = dcountif(tostring(parse_json(TelemetryApplicationInfo).ArtifactId), not(IsRunner))
by Command
| extend PctRunner = round(100.0 * Runner / Total, 1)
| order by Total desc
// 3) VHD rotation — 211 unique VhdId in 31 d during peak
SynapseMLLogs
| where TIMESTAMP between (datetime(2026-02-16) .. datetime(2026-03-19))
| where TelemetryApplicationInfo has "ChatMagics"
| where Message has "Telemetry: command=ignore"
| summarize Count = count(),
Notebooks = dcount(tostring(parse_json(TelemetryApplicationInfo).ArtifactId))
by VhdId
| top 20 by Count desc
// 4) Filter OUT the runner if you ever want a real-user-only view
SynapseMLLogs
| where TIMESTAMP > ago(30d)
| where TelemetryApplicationInfo has "ChatMagics"
| where Message has "Telemetry: command="
| where Tenant != "A365BBCRunner" // strip CI noise
| extend Command = extract(@"Telemetry: command=(\w+)", 1, Message)
| summarize Count = count() by Command
| order by Count desc
// 5) 30-day runner-vs-real-user split per command — drives the "Usage by command (30 d)" table
SynapseMLLogs
| where TIMESTAMP > ago(30d)
| where TelemetryApplicationInfo has "ChatMagics"
| where Message has "Telemetry: command="
| extend Command = extract(@"Telemetry: command=(\w+)", 1, Message)
| where isnotempty(Command)
| extend IsRunner = (Tenant == "A365BBCRunner")
| extend AppInfo = parse_json(TelemetryApplicationInfo)
| summarize Total = count(),
Runner = countif(IsRunner),
RealUser = countif(not(IsRunner)),
UniqueWorkspaces = dcount(Workspace),
UniqueArtifacts = dcount(tostring(AppInfo.ArtifactId)),
RunnerArtifacts = dcountif(tostring(AppInfo.ArtifactId), IsRunner),
RealUserArtifacts = dcountif(tostring(AppInfo.ArtifactId), not(IsRunner))
by Command
| extend PctRunner = round(100.0 * Runner / Total, 1)
| order by Total desc