Custom telemetry with Feature Telemetry and Session.LogMessage for BC
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
KQL (Kusto Query Language) is case-sensitive and similar to T-SQL. Statements are separated by pipe (|).
| Statement | Purpose | Example |
|---|---|---|
let | Define variable/constant | let days = 7; |
traces | Tabular statement (table name) | traces | where ... |
| Operator | Purpose | Example |
|---|---|---|
where | Filter rows | where timestamp > ago(24h) |
extend | Add calculated columns | extend duration = toint(customDimensions.alDurationMs) |
summarize | Aggregate data | summarize count() by eventId |
project | Select columns to output | project timestamp, eventId, message |
project-away | Exclude columns | project-away customDimensions |
order by / sort by | Sort results | order by timestamp desc |
| Function | Purpose | Example |
|---|---|---|
ago(timespan) | Time relative to now | ago(24h), ago(7d) |
tostring(value) | Convert to string | tostring(customDimensions.eventId) |
toint(value) | Convert to integer | toint(customDimensions.alDurationMs) |
toreal(value) | Convert to decimal | toreal(totimespan(customDimensions.serverExecutionTime)) |
count() | Count rows | summarize count() |
countif(predicate) | Conditional count | countif(isError) |
avg(), min(), max() | Aggregations | avg(duration) |
percentile(col, n) | Percentile calculation | percentile(duration, 95) |
bin(col, size) | Group into buckets | bin(timestamp, 1h) |
| Table | Content |
|---|---|
traces | All telemetry signals (except page views) |
pageViews | Page open events |
traces
| where timestamp > ago(24h)
| where customDimensions.eventId startswith "AL<PREFIX>-"
| project
timestamp,
eventId = tostring(customDimensions.eventId),
subCategory = tostring(customDimensions.alSubCategory),
featureName = tostring(customDimensions.alFeatureName),
message,
environmentName = tostring(customDimensions.environmentName),
companyName = tostring(customDimensions.alCompany)
| order by timestamp desctraces
| where timestamp > ago(24h)
| where customDimensions.eventId startswith "AL<PREFIX>-"
| where customDimensions.alSubCategory == "Error"
| project
timestamp,
eventId = tostring(customDimensions.eventId),
featureName = tostring(customDimensions.alFeatureName),
errorText = tostring(customDimensions.alErrorText),
callStack = tostring(customDimensions.alErrorCallStack),
environmentName = tostring(customDimensions.environmentName)
| order by timestamp desctraces
| where timestamp > ago(24h)
| where customDimensions.eventId startswith "AL<PREFIX>-"
| where customDimensions.alSubCategory == "Usage"
| project
timestamp,
eventId = tostring(customDimensions.eventId),
featureName = tostring(customDimensions.alFeatureName),
message,
environmentName = tostring(customDimensions.environmentName)
| order by timestamp desctraces
| where timestamp > ago(7d)
| where customDimensions.eventId startswith "AL<PREFIX>-"
| where customDimensions.alSubCategory == "Error"
| summarize
errorCount = count(),
lastOccurrence = max(timestamp)
by
eventId = tostring(customDimensions.eventId),
errorText = tostring(customDimensions.alErrorText)
| order by errorCount desctraces
| where timestamp > ago(7d)
| where customDimensions.eventId startswith "AL<PREFIX>-"
| extend isError = customDimensions.alSubCategory == "Error"
| summarize
total = count(),
errors = countif(isError),
success = countif(not(isError))
| extend
errorRate = round(100.0 * errors / total, 2),
successRate = round(100.0 * success / total, 2)traces
| where timestamp > ago(7d)
| where customDimensions.eventId startswith "AL<PREFIX>-"
| summarize
eventCount = count(),
errorCount = countif(customDimensions.alSubCategory == "Error")
by
environmentName = tostring(customDimensions.environmentName),
environmentType = tostring(customDimensions.environmentType)
| order by eventCount desctraces
| where timestamp > ago(7d)
| where customDimensions.eventId startswith "AL<PREFIX>-"
| summarize
eventCount = count(),
errorCount = countif(customDimensions.alSubCategory == "Error")
by
appVersion = tostring(customDimensions.alCallerAppVersion)
| order by appVersion descFeature Telemetry creates duplicate events by design. Use these patterns to de-duplicate:
traces
| where timestamp > ago(7d)
| where customDimensions.eventId startswith "AL<PREFIX>-"
| summarize
take_any(timestamp),
take_any(message)
by
eventId = tostring(customDimensions.eventId),
bin(timestamp, 1s),
documentNo = tostring(customDimensions.alDocumentNo)
| counttraces
| where timestamp > ago(7d)
| where customDimensions.eventId startswith "AL<PREFIX>-"
| where tostring(customDimensions.alDurationMs) != ""
// First de-duplicate
| summarize
take_any(timestamp),
durationMs = take_any(toint(customDimensions.alDurationMs))
by
eventId = tostring(customDimensions.eventId),
operation = tostring(customDimensions.alOperation),
bin(timestamp, 1s)
// Then calculate stats
| summarize
avgDuration = avg(durationMs),
maxDuration = max(durationMs),
minDuration = min(durationMs),
p95Duration = percentile(durationMs, 95),
callCount = count()
by operation
| order by avgDuration desctraces
| where timestamp > ago(24h)
| where customDimensions.eventId startswith "AL<PREFIX>-"
| extend
documentNo = tostring(customDimensions.alDocumentNo),
operation = tostring(customDimensions.alOperation),
httpStatus = toint(customDimensions.alHttpStatus),
durationMs = toint(customDimensions.alDurationMs),
url = tostring(customDimensions.alURL)
| project
timestamp,
eventId = tostring(customDimensions.eventId),
documentNo,
operation,
httpStatus,
durationMs,
url
| order by timestamp desctraces
| where timestamp > ago(7d)
| where customDimensions.eventId startswith "AL<PREFIX>-"
| where toint(customDimensions.alDurationMs) > 5000 // > 5 seconds
| project
timestamp,
eventId = tostring(customDimensions.eventId),
operation = tostring(customDimensions.alOperation),
durationMs = toint(customDimensions.alDurationMs),
documentNo = tostring(customDimensions.alDocumentNo)
| order by durationMs desctraces
| where timestamp > ago(30d)
| where customDimensions.eventId startswith "AL<PREFIX>-"
| where customDimensions.alSubCategory == "Uptake"
| summarize
discovered = countif(customDimensions.alFeatureUptakeStatus == "Discovered"),
setup = countif(customDimensions.alFeatureUptakeStatus == "Set up"),
used = countif(customDimensions.alFeatureUptakeStatus == "Used")
by featureName = tostring(customDimensions.alFeatureName)traces
| where timestamp > ago(30d)
| where customDimensions.eventId startswith "AL<PREFIX>-"
| where customDimensions.alSubCategory == "Usage"
| summarize
usageCount = count(),
lastUsed = max(timestamp)
by
companyName = tostring(customDimensions.alCompany),
environmentName = tostring(customDimensions.environmentName)
| order by usageCount desctraces
| where timestamp > ago(1h)
| where customDimensions.eventId startswith "AL<PREFIX>-"
| summarize
total = count(),
errors = countif(customDimensions.alSubCategory == "Error")
| where errors > 0 and (errors * 100.0 / total) > 10 // Alert if > 10% errorstraces
| where timestamp > ago(1h)
| where customDimensions.eventId startswith "AL<PREFIX>-"
| where customDimensions.alSubCategory == "Error"
| where customDimensions.eventId == "AL<PREFIX>-0002" // Specific error type
| count
| where Count > 5 // Alert if > 5 occurrences in 1 hour<PREFIX> with your actual EventId prefix (e.g., SST, APP)al prefix in Application Insights
DocumentNo → AI: alDocumentNoago(24h), ago(7d), etc.)