Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update Telemetry client with data outlined in spec #3737

Merged
merged 38 commits into from
May 23, 2023
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
3190435
Add cache details to token cache notification args
neha-bhargava Oct 6, 2022
2b2d6fd
Change code to make it more readable.
neha-bhargava Oct 7, 2022
4fe6bd7
Address comments
neha-bhargava Oct 7, 2022
169d95c
Address comments
neha-bhargava Oct 7, 2022
969867c
Remove unused imports
neha-bhargava Oct 11, 2022
c233b72
Change from dictionary to class
neha-bhargava Oct 12, 2022
09d2d35
Update comments and CacheUsed enum values
neha-bhargava Oct 12, 2022
c537f87
Merge branch 'main' into nebharg/AddCacheDetailsTelemetry
neha-bhargava Oct 12, 2022
fd6dd23
Removing the enum as this can be inferred from Latencies
neha-bhargava Oct 15, 2022
5449a7d
Merge branch 'nebharg/AddCacheDetailsTelemetry' of https://github.com…
neha-bhargava Oct 15, 2022
bd32bba
Merge remote-tracking branch 'origin/pmaytak/1' into nebharg/AddCache…
Mar 7, 2023
39ed3f0
Adding api event for credential type.
Mar 9, 2023
02dd568
Updating telemetry Data
Mar 10, 2023
e9e9ceb
Adding tests for new telemetry datapoints.
Mar 15, 2023
1b9644f
Adding telemetry cache test.
Mar 15, 2023
057e407
Merge branch 'main' into nebharg/AddCacheDetailsTelemetry
trwalke Mar 15, 2023
8477fc4
Merge remote-tracking branch 'origin/pmaytak/1' into nebharg/AddCache…
Mar 29, 2023
2df0d13
Refactoring
Mar 29, 2023
43ad450
Merge branch 'main' into nebharg/AddCacheDetailsTelemetry
Apr 20, 2023
18f153b
Refactoring
Apr 20, 2023
df4da2f
Adding scopes, resources and error message to telemetry
Apr 21, 2023
d7c655f
Apply suggestions from code review
trwalke Apr 25, 2023
2d1eb42
Merge remote-tracking branch 'origin/main' into nebharg/AddCacheDetai…
Apr 25, 2023
35b5c73
Updating scope parsing logic.
Apr 27, 2023
8a66797
Refactoring
Apr 28, 2023
1a88f21
Updating telemetry data points
May 3, 2023
1823be2
Merge branch 'main' into nebharg/AddCacheDetailsTelemetry
trwalke May 3, 2023
40d62f8
Test update
May 3, 2023
15896d2
Fix typo
May 3, 2023
d64f181
Test Fixes
May 3, 2023
9346d15
Merge branch 'main' into nebharg/AddCacheDetailsTelemetry
trwalke May 3, 2023
24d2bc3
Apply suggestions from code review
trwalke May 16, 2023
4e1bf52
Adding additional test
May 17, 2023
657a8cc
Merge branch 'main' into nebharg/AddCacheDetailsTelemetry
May 23, 2023
40a22d0
test fix
May 23, 2023
0be7992
Test Fix
May 23, 2023
cb4667f
Test Update
May 23, 2023
059b6e4
Merge branch 'main' into nebharg/AddCacheDetailsTelemetry
gladjohn May 23, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ public X509Certificate2 ClientCredentialCertificate
}
}



#endregion

#region Region
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,8 @@ private async Task RefreshCacheForReadOperationsAsync()
requestScopes: _requestParams.Scope,
requestTenantId: _requestParams.AuthorityManager.OriginalAuthority.TenantId,
identityLogger: _requestParams.RequestContext.Logger.IdentityLogger,
piiLoggingEnabled: _requestParams.RequestContext.Logger.PiiLoggingEnabled);
piiLoggingEnabled: _requestParams.RequestContext.Logger.PiiLoggingEnabled,
telemetryDatapoints: RequestContext.TelemetryDatapoints);

stopwatch.Start();
await TokenCacheInternal.OnBeforeAccessAsync(args).ConfigureAwait(false);
Expand All @@ -155,7 +156,8 @@ private async Task RefreshCacheForReadOperationsAsync()
requestScopes: _requestParams.Scope,
requestTenantId: _requestParams.AuthorityManager.OriginalAuthority.TenantId,
identityLogger: _requestParams.RequestContext.Logger.IdentityLogger,
piiLoggingEnabled: _requestParams.RequestContext.Logger.PiiLoggingEnabled);
piiLoggingEnabled: _requestParams.RequestContext.Logger.PiiLoggingEnabled,
telemetryDatapoints: RequestContext.TelemetryDatapoints);

await TokenCacheInternal.OnAfterAccessAsync(args).ConfigureAwait(false);
RequestContext.ApiEvent.DurationInCacheInMs += stopwatch.ElapsedMilliseconds;
Expand Down
26 changes: 26 additions & 0 deletions src/client/Microsoft.Identity.Client/Cache/CacheTypeUsed.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Microsoft.Identity.Client.Cache
{
/// <summary>
/// Identifies the type of cache used when accessing the cache.
/// </summary>
public enum CacheTypeUsed
{
/// <summary>
/// Specifies if the L1 cache is used
/// </summary>
L1Cache,
/// <summary>
/// Specifies if the L2 cache is used
/// </summary>
L2Cache
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Microsoft.Identity.Client.Core;
using Microsoft.Identity.Client.OAuth2;
using Microsoft.Identity.Client.PlatformsCommon.Interfaces;
using Microsoft.Identity.Client.TelemetryCore;
using Microsoft.Identity.Client.Utils;

namespace Microsoft.Identity.Client.Internal.ClientCredential
Expand All @@ -17,8 +18,11 @@ internal class CertificateAndClaimsClientCredential : IClientCredential
private readonly IDictionary<string, string> _claimsToSign;
private readonly bool _appendDefaultClaims;
private readonly string _base64EncodedThumbprint; // x5t
private bool _sendX5c;
public X509Certificate2 Certificate { get; }

public AssertionType AssertionType => _sendX5c ? AssertionType.CertificateWithSNI : AssertionType.Certificate;

public CertificateAndClaimsClientCredential(X509Certificate2 certificate, IDictionary<string, string> claimsToSign, bool appendDefaultClaims)
{
Certificate = certificate;
Expand All @@ -42,7 +46,9 @@ public Task AddConfidentialClientParametersAsync(
tokenEndpoint,
_claimsToSign,
_appendDefaultClaims);


_sendX5c = sendX5C;

string assertion = jwtToken.Sign(Certificate, _base64EncodedThumbprint, sendX5C);

oAuth2Client.AddBodyParameter(OAuth2Parameter.ClientAssertionType, OAuth2AssertionType.JwtBearer);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,15 @@
using Microsoft.Identity.Client.Core;
using Microsoft.Identity.Client.OAuth2;
using Microsoft.Identity.Client.PlatformsCommon.Interfaces;
using Microsoft.Identity.Client.TelemetryCore;
using Microsoft.Identity.Client.Utils;

namespace Microsoft.Identity.Client.Internal.ClientCredential
{
internal interface IClientCredential
{
AssertionType AssertionType { get; }

Task AddConfidentialClientParametersAsync(
OAuth2Client oAuth2Client,
ILoggerAdapter logger,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using Microsoft.Identity.Client.Core;
using Microsoft.Identity.Client.OAuth2;
using Microsoft.Identity.Client.PlatformsCommon.Interfaces;
using Microsoft.Identity.Client.TelemetryCore;
using Microsoft.Identity.Client.Utils;

namespace Microsoft.Identity.Client.Internal.ClientCredential
Expand All @@ -14,6 +15,8 @@ internal class SecretStringClientCredential : IClientCredential
{
internal string Secret { get; }

public AssertionType AssertionType => AssertionType.Secret;

public SecretStringClientCredential(string secret)
{
Secret = secret;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using Microsoft.Identity.Client.Core;
using Microsoft.Identity.Client.OAuth2;
using Microsoft.Identity.Client.PlatformsCommon.Interfaces;
using Microsoft.Identity.Client.TelemetryCore;
using Microsoft.Identity.Client.Utils;

namespace Microsoft.Identity.Client.Internal.ClientCredential
Expand All @@ -14,10 +15,13 @@ internal class SignedAssertionClientCredential : IClientCredential
{
private readonly string _signedAssertion;

public AssertionType AssertionType => AssertionType.UserProvided;

public SignedAssertionClientCredential(string signedAssertion)
{
_signedAssertion = signedAssertion;
}

public Task AddConfidentialClientParametersAsync(OAuth2Client oAuth2Client, ILoggerAdapter logger, ICryptographyManager cryptographyManager, string clientId, string tokenEndpoint, bool sendX5C, CancellationToken cancellationToken)
{
oAuth2Client.AddBodyParameter(OAuth2Parameter.ClientAssertionType, OAuth2AssertionType.JwtBearer);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@
using Microsoft.Identity.Client.Core;
using Microsoft.Identity.Client.OAuth2;
using Microsoft.Identity.Client.PlatformsCommon.Interfaces;
using Microsoft.Identity.Client.TelemetryCore;

namespace Microsoft.Identity.Client.Internal.ClientCredential
{
internal class SignedAssertionDelegateClientCredential : IClientCredential
{
internal Func<CancellationToken, Task<string>> _signedAssertionDelegate { get; }
internal Func<AssertionRequestOptions, Task<string>> _signedAssertionWithInfoDelegate { get; }
public AssertionType AssertionType => AssertionType.UserProvided;

[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public SignedAssertionDelegateClientCredential(Func<CancellationToken, Task<string>> signedAssertionDelegate)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.Threading;
using Microsoft.Identity.Client.Core;
using Microsoft.Identity.Client.Internal.Logger;
using Microsoft.Identity.Client.TelemetryCore;
using Microsoft.Identity.Client.TelemetryCore.Internal.Events;
using Microsoft.Identity.Client.TelemetryCore.TelemetryClient;
using Microsoft.IdentityModel.Abstractions;

namespace Microsoft.Identity.Client.Internal
Expand All @@ -24,6 +26,8 @@ internal class RequestContext

public CancellationToken UserCancellationToken { get; }

public TelemetryDatapoints TelemetryDatapoints { get; } = new TelemetryDatapoints();

public RequestContext(IServiceBundle serviceBundle, Guid correlationId, CancellationToken cancellationToken = default)
{
ServiceBundle = serviceBundle ?? throw new ArgumentNullException(nameof(serviceBundle));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ public async Task<AuthenticationResult> RunAsync(CancellationToken cancellationT
LogReturnedToken(authenticationResult);
UpdateTelemetry(sw, apiEvent, authenticationResult);
LogMetricsFromAuthResult(authenticationResult, AuthenticationRequestParameters.RequestContext.Logger);
LogSuccessfulTelemetryToClient(authenticationResult, telemetryEventDetails, telemetryClients);
LogSuccessfulTelemetryToClient(authenticationResult, AuthenticationRequestParameters.RequestContext.TelemetryDatapoints, telemetryEventDetails, telemetryClients);

return authenticationResult;
}
Expand Down Expand Up @@ -129,7 +129,7 @@ private void LogErrorTelemetryToClient(string errorCode, MsalTelemetryEventDetai
}
}

private void LogSuccessfulTelemetryToClient(AuthenticationResult authenticationResult, MsalTelemetryEventDetails telemetryEventDetails, ITelemetryClient[] telemetryClients)
private void LogSuccessfulTelemetryToClient(AuthenticationResult authenticationResult, TelemetryDatapoints telemetryDatapoints, MsalTelemetryEventDetails telemetryEventDetails, ITelemetryClient[] telemetryClients)
{
if (telemetryClients.HasEnabledClients(TelemetryConstants.AcquireTokenEventName))
{
Expand All @@ -139,9 +139,20 @@ private void LogSuccessfulTelemetryToClient(AuthenticationResult authenticationR
telemetryEventDetails.SetProperty(TelemetryConstants.DurationInCache, authenticationResult.AuthenticationResultMetadata.DurationInCacheInMs);
telemetryEventDetails.SetProperty(TelemetryConstants.DurationInHttp, authenticationResult.AuthenticationResultMetadata.DurationInHttpInMs);
telemetryEventDetails.SetProperty(TelemetryConstants.Succeeded, true);
telemetryEventDetails.SetProperty(TelemetryConstants.PopToken, authenticationResult.TokenType.Equals(Constants.PoPTokenType));
telemetryEventDetails.SetProperty(TelemetryConstants.TokenType, nameof(AuthenticationRequestParameters.RequestContext.ApiEvent.TokenType));
telemetryEventDetails.SetProperty(TelemetryConstants.RemainingLifetime, (authenticationResult.ExpiresOn - DateTime.Now).TotalMilliseconds);
telemetryEventDetails.SetProperty(TelemetryConstants.ActivityId, authenticationResult.CorrelationId);
telemetryEventDetails.SetProperty(TelemetryConstants.RefreshOn,
authenticationResult.AuthenticationResultMetadata.RefreshOn.HasValue ?
DateTimeHelpers.DateTimeToUnixTimestampMilliseconds(authenticationResult.AuthenticationResultMetadata.RefreshOn.Value)
: 0);
telemetryEventDetails.SetProperty(TelemetryConstants.AssertionType, nameof(AuthenticationRequestParameters.RequestContext.ApiEvent.AssertionType));
telemetryEventDetails.SetProperty(TelemetryConstants.Endpoint, AuthenticationRequestParameters.Authority.AuthorityInfo.CanonicalAuthority.ToString());
if (telemetryDatapoints.CacheTypeUsed != null)
{
telemetryEventDetails.SetProperty(TelemetryConstants.CacheUsed, nameof(telemetryDatapoints.CacheTypeUsed));
}

}
}

Expand Down Expand Up @@ -193,13 +204,29 @@ private ApiEvent InitializeApiEvent(string accountId)
apiEvent.IsLegacyCacheEnabled = AuthenticationRequestParameters.RequestContext.ServiceBundle.Config.LegacyCacheCompatibilityEnabled;
apiEvent.CacheInfo = CacheRefreshReason.NotApplicable;
apiEvent.TokenType = AuthenticationRequestParameters.AuthenticationScheme.TelemetryTokenType;
apiEvent.AssertionType = GetAssertionType();

// Give derived classes the ability to add or modify fields in the telemetry as needed.
EnrichTelemetryApiEvent(apiEvent);

return apiEvent;
}

private AssertionType GetAssertionType()
{
if (ServiceBundle.Config.UseManagedIdentity)
{
return AssertionType.MSI;
}

if (AuthenticationRequestParameters.OnBeforeTokenRequestHandler != null)
{
return AssertionType.TokenRequestHandler;
}

return (AssertionType)ServiceBundle.Config.ClientCredential.AssertionType;
}

protected async Task<AuthenticationResult> CacheTokenResponseAndCreateAuthenticationResultAsync(MsalTokenResponse msalTokenResponse)
{
// developer passed in user object.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Microsoft.Identity.Client.TelemetryCore
{
internal enum AssertionType
{
Certificate,
CertificateWithSNI,
Secret,
UserProvided,
MSI,
TokenRequestHandler
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -115,5 +115,7 @@ public string TokenTypeString
{
get => TokenType.HasValue ? TokenType.Value.ToString("D") : null;
}

public AssertionType AssertionType { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using Microsoft.Identity.Client.Cache;
using Microsoft.IdentityModel.Abstractions;

namespace Microsoft.Identity.Client.TelemetryCore.TelemetryClient
{
/// <summary>
/// Stores the cache details to log to <see cref="ITelemetryClient"/>.
/// </summary>
public class TelemetryDatapoints
{
/// <summary>
/// Total latency of L1 cache access. This data is captured in MSAL when accessing the internal cache or Microsoft.Identity.Web when accessing the memory cache.
/// </summary>
public CacheTypeUsed? CacheTypeUsed { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ internal static class TelemetryConstants
public const string ConfigurationUpdateEventName = "config_update";
public const string MsalVersion = "MsalVersion";
public const string RemainingLifetime = "RemainingLifetime";
public const string PopToken = "PopToken";
public const string TokenType = "TokenType";
public const string TokenSource = "TokenSource";
public const string CacheInfoTelemetry = "CacheInfoTelemetry";
public const string ErrorCode = "ErrorCode";
Expand All @@ -32,7 +32,13 @@ internal static class TelemetryConstants
public const string DurationInHttp = "DurationInHttp";
public const string ActivityId = "ActivityId";
public const string Resource = "Resource";
public const string RefreshOn = "RefreshOn";
public const string CacheUsed = "CacheUsed";
public const string L1Latency = "L1Latency";
public const string L2Latency = "L2Latency";
public const string AssertionType = "AssertionType";
public const string Endpoint = "Endpoint";

#endregion
#endregion
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,8 @@ async Task<Tuple<MsalAccessTokenCacheItem, MsalIdTokenCacheItem, Account>> IToke
requestScopes: requestParams.Scope,
requestTenantId: requestParams.AuthorityManager.OriginalAuthority.TenantId,
identityLogger: requestParams.RequestContext.Logger.IdentityLogger,
piiLoggingEnabled: requestParams.RequestContext.Logger.PiiLoggingEnabled);
piiLoggingEnabled: requestParams.RequestContext.Logger.PiiLoggingEnabled,
telemetryDatapoints: requestParams.RequestContext.TelemetryDatapoints);

Stopwatch sw = Stopwatch.StartNew();

Expand Down Expand Up @@ -249,7 +250,8 @@ async Task<Tuple<MsalAccessTokenCacheItem, MsalIdTokenCacheItem, Account>> IToke
requestScopes: requestParams.Scope,
requestTenantId: requestParams.AuthorityManager.OriginalAuthority.TenantId,
identityLogger: requestParams.RequestContext.Logger.IdentityLogger,
piiLoggingEnabled: requestParams.RequestContext.Logger.PiiLoggingEnabled);
piiLoggingEnabled: requestParams.RequestContext.Logger.PiiLoggingEnabled,
telemetryDatapoints: requestParams.RequestContext.TelemetryDatapoints);

Stopwatch sw = Stopwatch.StartNew();
await tokenCacheInternal.OnAfterAccessAsync(args).ConfigureAwait(false);
Expand Down Expand Up @@ -743,7 +745,8 @@ internal async Task ExpireAllAccessTokensForTestAsync()
requestScopes: null,
requestTenantId: null,
identityLogger: null,
piiLoggingEnabled: false);
piiLoggingEnabled: false,
telemetryDatapoints: new TelemetryCore.TelemetryClient.TelemetryDatapoints());

await tokenCacheInternal.OnAfterAccessAsync(args).ConfigureAwait(false);
}
Expand Down Expand Up @@ -1176,7 +1179,8 @@ async Task ITokenCacheInternal.RemoveAccountAsync(IAccount account, Authenticati
requestScopes: requestParameters.Scope,
requestTenantId: requestParameters.AuthorityManager.OriginalAuthority.TenantId,
identityLogger: requestParameters.RequestContext.Logger.IdentityLogger,
piiLoggingEnabled: requestParameters.RequestContext.Logger.PiiLoggingEnabled);
piiLoggingEnabled: requestParameters.RequestContext.Logger.PiiLoggingEnabled,
telemetryDatapoints: requestParameters.RequestContext.TelemetryDatapoints);

await tokenCacheInternal.OnBeforeAccessAsync(args).ConfigureAwait(false);
await tokenCacheInternal.OnBeforeWriteAsync(args).ConfigureAwait(false);
Expand Down Expand Up @@ -1211,7 +1215,8 @@ async Task ITokenCacheInternal.RemoveAccountAsync(IAccount account, Authenticati
requestScopes: requestParameters.Scope,
requestTenantId: requestParameters.AuthorityManager.OriginalAuthority.TenantId,
identityLogger: requestParameters.RequestContext.Logger.IdentityLogger,
piiLoggingEnabled: requestParameters.RequestContext.Logger.PiiLoggingEnabled);
piiLoggingEnabled: requestParameters.RequestContext.Logger.PiiLoggingEnabled,
telemetryDatapoints: requestParameters.RequestContext.TelemetryDatapoints);

await tokenCacheInternal.OnAfterAccessAsync(args).ConfigureAwait(false);
}
Expand Down
Loading