microsoft/teams.net
Publicmirrored fromhttps://github.com/microsoft/teams.netAvailable
core/src/Microsoft.Teams.Apps/Diagnostics/AppsTelemetry.cs
190lines · modecode
| 1 | // Copyright (c) Microsoft Corporation. |
| 2 | // Licensed under the MIT License. |
| 3 | |
| 4 | using System.Diagnostics; |
| 5 | using System.Diagnostics.Metrics; |
| 6 | |
| 7 | namespace Microsoft.Teams.Apps.Diagnostics; |
| 8 | |
| 9 | /// <summary> |
| 10 | /// Singletons for the Apps-level <see cref="ActivitySource"/>, <see cref="Meter"/>, and instruments. |
| 11 | /// Internal to <c>Microsoft.Teams.Apps</c>. |
| 12 | /// </summary> |
| 13 | internal static class AppsTelemetry |
| 14 | { |
| 15 | private const string s_version = ThisAssembly.NuGetPackageVersion; |
| 16 | |
| 17 | public static readonly ActivitySource Source = |
| 18 | new(TeamsBotApplicationTelemetry.ActivitySourceName, s_version); |
| 19 | |
| 20 | public static readonly Meter Meter = |
| 21 | new(TeamsBotApplicationTelemetry.MeterName, s_version); |
| 22 | |
| 23 | public static readonly Counter<long> HandlerDispatched = |
| 24 | Meter.CreateCounter<long>(Metrics.HandlerDispatched, description: "Total handler invocations dispatched by the router."); |
| 25 | |
| 26 | public static readonly Histogram<double> HandlerDuration = |
| 27 | Meter.CreateHistogram<double>(Metrics.HandlerDuration, unit: "ms", description: "Duration of individual handler invocations."); |
| 28 | |
| 29 | public static readonly Counter<long> HandlerFailures = |
| 30 | Meter.CreateCounter<long>(Metrics.HandlerFailures, description: "Total handler invocations that threw an exception."); |
| 31 | |
| 32 | public static readonly Counter<long> HandlerUnmatched = |
| 33 | Meter.CreateCounter<long>(Metrics.HandlerUnmatched, description: "Total activities that found no matching route."); |
| 34 | |
| 35 | // ── State instruments ──────────────────────────────────────────────── |
| 36 | |
| 37 | public static readonly Histogram<double> StateLoadDuration = |
| 38 | Meter.CreateHistogram<double>(Metrics.StateLoadDuration, unit: "ms", description: "Duration of state load from cache."); |
| 39 | |
| 40 | public static readonly Histogram<double> StateSaveDuration = |
| 41 | Meter.CreateHistogram<double>(Metrics.StateSaveDuration, unit: "ms", description: "Duration of state save to cache."); |
| 42 | |
| 43 | public static readonly Counter<long> StateCacheErrors = |
| 44 | Meter.CreateCounter<long>(Metrics.StateCacheErrors, description: "Total cache operation failures for turn state."); |
| 45 | |
| 46 | public static readonly Histogram<long> StateBytesRead = |
| 47 | Meter.CreateHistogram<long>(Metrics.StateBytesRead, unit: "By", description: "Bytes read from cache per state load."); |
| 48 | |
| 49 | public static readonly Histogram<long> StateBytesWritten = |
| 50 | Meter.CreateHistogram<long>(Metrics.StateBytesWritten, unit: "By", description: "Bytes written to cache per state save."); |
| 51 | |
| 52 | // ── OAuth instruments ──────────────────────────────────────────────── |
| 53 | |
| 54 | public static readonly Counter<long> OAuthOperationCount = |
| 55 | Meter.CreateCounter<long>(Metrics.OAuthOperations, description: "Total OAuth flow operations attempted. For verify_state and signin_failure invokes, each per-flow attempt is counted independently in multi-connection deployments."); |
| 56 | |
| 57 | public static readonly Histogram<double> OAuthOperationDuration = |
| 58 | Meter.CreateHistogram<double>(Metrics.OAuthOperationDuration, unit: "ms", description: "Duration of OAuth flow operations."); |
| 59 | |
| 60 | public static readonly Counter<long> OAuthErrors = |
| 61 | Meter.CreateCounter<long>(Metrics.OAuthErrors, description: "Total OAuth flow operations that failed with an unexpected exception. Expected protocol fallbacks (HTTP 404/400/412 from the Token Service) are not counted here; they are recorded as oauth.result=failure on teams.oauth.operations instead."); |
| 62 | |
| 63 | public static class Spans |
| 64 | { |
| 65 | public const string Handler = "handler"; |
| 66 | public const string StateLoad = "state.load"; |
| 67 | public const string StateSave = "state.save"; |
| 68 | public const string StateDelete = "state.delete"; |
| 69 | |
| 70 | // OAuth spans |
| 71 | public const string OAuthSignIn = "oauth.signin"; |
| 72 | public const string OAuthSignOut = "oauth.signout"; |
| 73 | public const string OAuthGetToken = "oauth.get_token"; |
| 74 | public const string OAuthTokenExchange = "oauth.token_exchange"; |
| 75 | public const string OAuthVerifyState = "oauth.verify_state"; |
| 76 | public const string OAuthSignInFailure = "oauth.signin_failure"; |
| 77 | public const string OAuthConnectionStatus = "oauth.connection_status"; |
| 78 | } |
| 79 | |
| 80 | public static class Tags |
| 81 | { |
| 82 | public const string HandlerType = "handler.type"; |
| 83 | public const string HandlerDispatch = "handler.dispatch"; |
| 84 | public const string ActivityType = "activity.type"; |
| 85 | public const string InvokeName = "invoke.name"; |
| 86 | |
| 87 | // State tags |
| 88 | public const string StateConversationHit = "state.conversation.hit"; |
| 89 | public const string StateUserHit = "state.user.hit"; |
| 90 | public const string StateConversationDirty = "state.conversation.dirty"; |
| 91 | public const string StateUserDirty = "state.user.dirty"; |
| 92 | public const string StateBytesRead = "state.bytes.read"; |
| 93 | public const string StateBytesWritten = "state.bytes.written"; |
| 94 | public const string Operation = "operation"; |
| 95 | |
| 96 | // OAuth tags |
| 97 | public const string OAuthConnection = "oauth.connection"; |
| 98 | public const string OAuthOperation = "oauth.operation"; |
| 99 | public const string OAuthResult = "oauth.result"; |
| 100 | public const string OAuthErrorType = "oauth.error.type"; |
| 101 | public const string OAuthFailureCode = "oauth.failure.code"; |
| 102 | public const string OAuthCallbackInvoked = "oauth.callback.invoked"; |
| 103 | public const string InvokeResponseStatus = "invoke.response.status"; |
| 104 | } |
| 105 | |
| 106 | public static class Metrics |
| 107 | { |
| 108 | public const string HandlerDispatched = "teams.handler.dispatched"; |
| 109 | public const string HandlerDuration = "teams.handler.duration"; |
| 110 | public const string HandlerFailures = "teams.handler.failures"; |
| 111 | public const string HandlerUnmatched = "teams.handler.unmatched"; |
| 112 | |
| 113 | // State metrics |
| 114 | public const string StateLoadDuration = "teams.state.load.duration"; |
| 115 | public const string StateSaveDuration = "teams.state.save.duration"; |
| 116 | public const string StateCacheErrors = "teams.state.cache.errors"; |
| 117 | public const string StateBytesRead = "teams.state.bytes.read"; |
| 118 | public const string StateBytesWritten = "teams.state.bytes.written"; |
| 119 | |
| 120 | // OAuth metrics |
| 121 | public const string OAuthOperations = "teams.oauth.operations"; |
| 122 | public const string OAuthOperationDuration = "teams.oauth.operation.duration"; |
| 123 | public const string OAuthErrors = "teams.oauth.errors"; |
| 124 | } |
| 125 | |
| 126 | /// <summary> |
| 127 | /// Values used for the <see cref="Tags.OAuthOperation"/> tag. |
| 128 | /// Low cardinality: one of seven well-known operation names. |
| 129 | /// </summary> |
| 130 | public static class OAuthOperations |
| 131 | { |
| 132 | public const string SignIn = "signin"; |
| 133 | public const string SignOut = "signout"; |
| 134 | public const string GetToken = "get_token"; |
| 135 | public const string TokenExchange = "token_exchange"; |
| 136 | public const string VerifyState = "verify_state"; |
| 137 | public const string SignInFailure = "signin_failure"; |
| 138 | public const string ConnectionStatus = "connection_status"; |
| 139 | } |
| 140 | |
| 141 | /// <summary> |
| 142 | /// Values used for the <see cref="Tags.OAuthResult"/> tag. |
| 143 | /// </summary> |
| 144 | public static class OAuthResults |
| 145 | { |
| 146 | /// <summary>SignIn returned a cached token without sending an OAuthCard.</summary> |
| 147 | public const string Cached = "cached"; |
| 148 | /// <summary>SignIn sent an OAuthCard because no cached token was found.</summary> |
| 149 | public const string CardSent = "card_sent"; |
| 150 | /// <summary>GetToken found a cached token in the Token Store.</summary> |
| 151 | public const string Hit = "hit"; |
| 152 | /// <summary>GetToken found no cached token in the Token Store.</summary> |
| 153 | public const string Miss = "miss"; |
| 154 | /// <summary>Operation completed successfully.</summary> |
| 155 | public const string Success = "success"; |
| 156 | /// <summary>Expected protocol failure (e.g., Token Service returned 404/400/412, or null state).</summary> |
| 157 | public const string Failure = "failure"; |
| 158 | /// <summary>Duplicate signin/tokenExchange invoke; deduplicated to a 200 no-op.</summary> |
| 159 | public const string Duplicate = "duplicate"; |
| 160 | /// <summary>verify_state attempted on a flow whose connection didn't match the code.</summary> |
| 161 | public const string NoToken = "no_token"; |
| 162 | /// <summary>signin_failure invoke acknowledged and forwarded to the OnSignInFailure callback.</summary> |
| 163 | public const string Notified = "notified"; |
| 164 | } |
| 165 | |
| 166 | /// <summary> |
| 167 | /// Values used for the <see cref="Tags.OAuthErrorType"/> tag. |
| 168 | /// Set only on the <see cref="OAuthErrors"/> counter and on spans when an unexpected exception escapes. |
| 169 | /// </summary> |
| 170 | public static class OAuthErrorTypes |
| 171 | { |
| 172 | public const string HttpError = "http_error"; |
| 173 | public const string InvalidOperation = "invalid_op"; |
| 174 | public const string EmptyToken = "empty_token"; |
| 175 | } |
| 176 | |
| 177 | /// <summary> |
| 178 | /// Names of low-cardinality span events emitted by OAuth flows. |
| 179 | /// </summary> |
| 180 | public static class OAuthEvents |
| 181 | { |
| 182 | public const string CardSent = "oauth.card.sent"; |
| 183 | } |
| 184 | |
| 185 | /// <summary> |
| 186 | /// Special <see cref="Tags.OAuthConnection"/> value used by operations that span all connections |
| 187 | /// (e.g., <c>connection_status</c> returns the status of every registered OAuth connection). |
| 188 | /// </summary> |
| 189 | public const string OAuthAllConnections = "all"; |
| 190 | } |
| 191 | |