OpenTelemetry with Azure Monitor
In order to log OpenTelemetry signals into Azure Monitor, you need to obtain an Azure Monitor connection string. In order to set up Azure Monitor with log collection, follow the Azure Monitor guide from Microsoft Learn.
In short, in an Azure resource group you will need:
- One
Log Analytics Workspaceresource. - One
Application Insightsresource that uses the analytics workspace resource. - The
Application Insightsresource has the connection string listed on the Overview page.
Afterwards, edit appsettings.json for the ShareAspace Service Host and all of
the installed extensions to include APPLICATIONINSIGHTS_CONNECTION_STRING at
the root level:
{
"Logging": {
// ...
},
// ...
"APPLICATIONINSIGHTS_CONNECTION_STRING": "InstrumentationKey=REDACTED;IngestionEndpoint=REDACTED;LiveEndpoint=REDACTED;ApplicationId=REDACTED"
}
The following properties may consequently be removed from the configuration files:
OTEL_EXPORTER_OTLP_ENDPOINTOTEL_EXPORTER_OTLP_PROTOCOLOTEL_EXPORTER_OTLP_HEADERS
Common use cases
The following section lists some useful KQL queries that can be used against the traces and exceptions tables in Application Insights.
Many of the queries below follow a common pattern:
- first identifying relevant
SpanIdorConnectionIdvalues, then joining back - to the
tracestable to reconstruct the complete activity context.
User activities
Download
List all file downloads of managed files.
traces
| where message contains "File Downloaded"
Check request start and finish surrounding the file download event. Each SpanId is its own download.
traces
| extend
SpanId = tostring(customDimensions["SpanId"])
| where message contains "File Downloaded"
| project SpanId
| distinct SpanId
| join kind=inner (
traces
| extend
SpanId = tostring(customDimensions["SpanId"])
) on SpanId
| order by timestamp desc
Delete
List all delete requests (start and finish).
traces
| where customDimensions["Method"] == "DELETE"
List all traces for what the delete request did (between start and finish). Each SpanId is its own delete request trace.
traces
| extend
SpanId = tostring(customDimensions["SpanId"])
| where customDimensions["Method"] == "DELETE"
| project SpanId
| distinct SpanId
| join kind=inner (
traces
| extend
SpanId = tostring(customDimensions["SpanId"])
) on SpanId
| order by timestamp desc
Authentication token exchange ("Sign in")
While there is no explicit “sign in” in ShareAspace, a user exchanges an ID token for a ShareAspace access token by performing a POST request to authorization/token.
traces
| where customDimensions["Path"] contains "authorization/token"
To see what user "signed in", one can combine the token trade with the connection id. When using ShareAspace web, a user will request its own user information after login. Each unique ConnectionId represents one "sign in".
traces
| extend
ConnectionId = tostring(customDimensions["ConnectionId"])
| where customDimensions["Path"] contains "authorization/token"
| project ConnectionId
| distinct ConnectionId
| join kind=inner (
traces
| extend
ConnectionId = tostring(customDimensions["ConnectionId"])
| where message startswith "Request starting"
| where customDimensions["RequestPath"] startswith "/collection/user/"
) on ConnectionId
| order by timestamp asc
Failure identification
User trace
Tracing all failures from request start to finish. Each SpanId is its own failure request trace.
traces
| extend
StatusCode = toint(customDimensions["StatusCode"]),
SpanId = tostring(customDimensions["SpanId"])
| where StatusCode == 500
| project SpanId
| distinct SpanId
| join kind=inner (
traces
| extend
SpanId = tostring(customDimensions["SpanId"])
) on SpanId
| order by timestamp desc
Check what the user was doing in the "session" where the failure happened.
traces
| extend
StatusCode = toint(customDimensions["StatusCode"]),
SpanId = tostring(customDimensions["SpanId"]),
ConnectionId = tostring(customDimensions["ConnectionId"])
| where StatusCode == 500
| project ConnectionId
| distinct ConnectionId
| join kind=inner (
traces
| extend
ConnectionId = tostring(customDimensions["ConnectionId"])
) on ConnectionId
| order by timestamp desc
Check what user had the issue.
traces
| extend
StatusCode = toint(customDimensions["StatusCode"]),
SpanId = tostring(customDimensions["SpanId"]),
ConnectionId = tostring(customDimensions["ConnectionId"])
| where StatusCode == 500
| project ConnectionId
| distinct ConnectionId
| join kind=inner (
traces
| extend
ConnectionId = tostring(customDimensions["ConnectionId"])
) on ConnectionId
| where customDimensions["RequestPath"] startswith "/collection/user/"
| order by timestamp desc
System activities
Host stop activities
traces
| extend
EventId = tostring(customDimensions["EventId"]),
EventName = tostring(customDimensions["EventName"])
| where EventName == "Stopped"
or EventName == "Stop"
or EventName == "AllServicesStopped"
Indexing activity
traces
| extend
WorkName = tostring(customDimensions["WorkName"]),
SpanId = tostring(customDimensions["SpanId"])
| where WorkName == "IndexRebuildingWork"
Checkpoint start to finish
traces
| extend
SpanId = tostring(customDimensions["SpanId"]),
EventName = tostring(customDimensions["EventName"])
| where EventName == "CheckpointStarted"
or EventName == "CheckpointFinished"
Each SpanId represents everything that happened during one checkpoint activity.
traces
| extend
SpanId = tostring(customDimensions["SpanId"])
| where message == "Checkpoint started"
| project SpanId
| distinct SpanId
| join kind=inner (
traces
| extend
SpanId = tostring(customDimensions["SpanId"])
) on SpanId
| order by timestamp asc
Space create
List all space create requests.
traces
| extend
RequestPath = tostring(customDimensions["RequestPath"]),
SpanId = tostring(customDimensions["SpanId"])
| where customDimensions["typeName"] == "SpaceBootstrapWork"
| where customDimensions["EventName"] == "RunWorkStartedAfterWaitingForSlot"
Everything that happened during space create. Each unique SpanId represents one space create.
traces
| extend
RequestPath = tostring(customDimensions["RequestPath"]),
SpanId = tostring(customDimensions["SpanId"])
| where customDimensions["typeName"] == "SpaceBootstrapWork"
| where customDimensions["EventName"] == "RunWorkStartedAfterWaitingForSlot"
| project SpanId
| distinct SpanId
| join kind=inner (
traces
| extend
SpanId = tostring(customDimensions["SpanId"])
) on SpanId
| order by timestamp desc
Similar examples:
traces
| extend
ConnectionId = tostring(customDimensions["ConnectionId"])
| where customDimensions["Method"] == "POST"
| where customDimensions["Path"] startswith "/collection/space/"
| project ConnectionId
| distinct ConnectionId
| join kind=inner (
traces
| extend
ConnectionId = tostring(customDimensions["ConnectionId"])
) on ConnectionId
| order by timestamp desc
traces
| extend
SpanId = tostring(customDimensions["SpanId"])
| where customDimensions["Method"] == "POST"
| where customDimensions["Path"] startswith "/collection/space/"
| project SpanId
| distinct SpanId
| join kind=inner (
traces
| extend
SpanId = tostring(customDimensions["SpanId"])
) on SpanId
| order by timestamp desc
License limits
It is only possible to find blocking license limits like exceeding number of origins, participants, or users. Unit-of-information and disk space is not blocking.
exceptions
| extend
SpanId = tostring(customDimensions["SpanId"])
| where outerMessage contains "license limitation"
exceptions
| extend
SpanId = tostring(customDimensions["SpanId"])
| where outerMessage contains "license limitation"
| distinct SpanId
| join kind=inner (
traces
| extend
SpanId = tostring(customDimensions["SpanId"])
) on SpanId
| order by timestamp desc
Request limits
Requests that hit the request limiter (i.e. requests returning status code 429 - Too many requests).
traces
| extend
StatusCode = toint(customDimensions["StatusCode"]),
SpanId = tostring(customDimensions["SpanId"])
| where StatusCode == 429
| order by timestamp desc
Other requests that happened around the time of the too many requests responses.
traces
| extend
StatusCode = toint(customDimensions["StatusCode"]),
ConnectionId = tostring(customDimensions["ConnectionId"])
| where StatusCode == 429
| project ConnectionId
| distinct ConnectionId
| join kind=inner (
traces
| extend
ConnectionId = tostring(customDimensions["ConnectionId"])
) on ConnectionId
| order by timestamp desc