Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
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
Prev Previous commit
Next Next commit
Add telemetry, logging, and fix overall logic
  • Loading branch information
GeoK committed May 30, 2025
commit f0fe8f82d841fbdbe545c99bcccd3a358dd4eee5
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,8 @@ await ValidateJWEAsync(jsonWebToken, validationParameters, currentConfiguration)
{
_telemetryClient.IncrementConfigurationRefreshRequestCounter(
validationParameters.ConfigurationManager.MetadataAddress,
TelemetryConstants.Protocols.Lkg);
TelemetryConstants.Protocols.Lkg,
TelemetryConstants.Protocols.IrrelevantConfigurationSource);

validationParameters.ConfigurationManager.RequestRefresh();
validationParameters.RefreshBeforeValidation = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,8 +231,19 @@ private async Task<T> GetConfigurationNonBlockingAsync(CancellationToken cancel)
if (ConfigurationEventHandler != null)
{
var configurationRetrieved = await HandleBeforeRetrieveAsync(cancel).ConfigureAwait(false);
if (configurationRetrieved)
return _currentConfiguration; // TODO check if everything has been done

// replicate the behavior of successful retrieval from endpoint
if (configurationRetrieved != null && configurationRetrieved.Configuration != null)
{
TelemetryClient.IncrementConfigurationRefreshRequestCounter(
MetadataAddress,
TelemetryConstants.Protocols.FirstRefresh,
TelemetryConstants.Protocols.HandlerAsConfigurationSource
);

UpdateConfiguration(configurationRetrieved.Configuration, configurationRetrieved.RetrievalTime);
return _currentConfiguration;
}
}

// Don't use the individual CT here, this is a shared operation that shouldn't be affected by an individual's cancellation.
Expand All @@ -259,7 +270,9 @@ private async Task<T> GetConfigurationNonBlockingAsync(CancellationToken cancel)

TelemetryClient.IncrementConfigurationRefreshRequestCounter(
MetadataAddress,
TelemetryConstants.Protocols.FirstRefresh);
TelemetryConstants.Protocols.FirstRefresh,
TelemetryConstants.Protocols.EndpointAsConfigurationSource
);

UpdateConfiguration(configuration, TimeProvider.GetUtcNow().UtcDateTime);
}
Expand All @@ -270,6 +283,7 @@ private async Task<T> GetConfigurationNonBlockingAsync(CancellationToken cancel)
TelemetryClient.IncrementConfigurationRefreshRequestCounter(
MetadataAddress,
TelemetryConstants.Protocols.FirstRefresh,
TelemetryConstants.Protocols.EndpointAsConfigurationSource,
ex);

LogHelper.LogExceptionMessage(
Expand All @@ -292,7 +306,8 @@ private async Task<T> GetConfigurationNonBlockingAsync(CancellationToken cancel)
{
TelemetryClient.IncrementConfigurationRefreshRequestCounter(
MetadataAddress,
TelemetryConstants.Protocols.Automatic);
TelemetryConstants.Protocols.Automatic,
TelemetryConstants.Protocols.IrrelevantConfigurationSource);

_ = Task.Run(UpdateCurrentConfiguration, CancellationToken.None);
}
Expand Down Expand Up @@ -327,8 +342,11 @@ private void UpdateCurrentConfiguration()
if (ConfigurationEventHandler != null)
{
var configurationRetrieved = HandleBeforeRetrieveAsync().ConfigureAwait(false).GetAwaiter().GetResult();
if (configurationRetrieved)
return; // TODO check if everything has been done
if (configurationRetrieved != null && configurationRetrieved.Configuration != null)
{
UpdateConfiguration(configurationRetrieved.Configuration, configurationRetrieved.RetrievalTime);
return;
}
}

T configuration = _configRetriever.GetConfigurationAsync(
Expand All @@ -339,6 +357,7 @@ private void UpdateCurrentConfiguration()
var elapsedTime = TimeProvider.GetElapsedTime(startTimestamp);
TelemetryClient.LogConfigurationRetrievalDuration(
MetadataAddress,
TelemetryConstants.Protocols.EndpointAsConfigurationSource,
elapsedTime);

if (_configValidator == null)
Expand All @@ -365,6 +384,7 @@ private void UpdateCurrentConfiguration()
var elapsedTime = TimeProvider.GetElapsedTime(startTimestamp);
TelemetryClient.LogConfigurationRetrievalDuration(
MetadataAddress,
TelemetryConstants.Protocols.EndpointAsConfigurationSource,
elapsedTime,
ex);

Expand Down Expand Up @@ -401,16 +421,10 @@ private void UpdateConfiguration(T configuration, DateTimeOffset retrievalTime)
}
catch (Exception ex)
{
TelemetryClient.IncrementConfigurationRefreshRequestCounter(
MetadataAddress,
TelemetryConstants.Protocols.FirstRefresh, // todo is this true
ex); // TODO new dimension

// todo new logs
LogHelper.LogExceptionMessage(
new InvalidOperationException(
LogHelper.FormatInvariant(
"IDX20817: Exception occurred while notifying configuration update handler. MetadataAddress: '{0}', Exception: '{1}'.",
LogMessages.IDX20812,
LogHelper.MarkAsNonPII(MetadataAddress ?? "null"),
ex),
ex));
Expand Down Expand Up @@ -458,7 +472,8 @@ private void RequestRefreshBackgroundThread()
{
TelemetryClient.IncrementConfigurationRefreshRequestCounter(
MetadataAddress,
TelemetryConstants.Protocols.Manual);
TelemetryConstants.Protocols.Manual,
TelemetryConstants.Protocols.IrrelevantConfigurationSource);

_isFirstRefreshRequest = false;
if (Interlocked.CompareExchange(ref _configurationRetrieverState, ConfigurationRetrieverRunning, ConfigurationRetrieverIdle) == ConfigurationRetrieverIdle)
Expand All @@ -469,65 +484,62 @@ private void RequestRefreshBackgroundThread()
}
}

private async Task<bool> HandleBeforeRetrieveAsync(CancellationToken cancel = default)
private async Task<ConfigurationEventHandlerResult<T>> HandleBeforeRetrieveAsync(CancellationToken cancel = default)
{
long beforeHandlerTimestamp = TimeProvider.GetTimestamp();
#pragma warning disable CA1031 // Do not catch general exception types
try
{
var cachedResult = await ConfigurationEventHandler.BeforeRetrieveAsync(MetadataAddress, cancel).ConfigureAwait(false);
if (cachedResult != null && cachedResult.Configuration != null)
var handlerResult = await ConfigurationEventHandler.BeforeRetrieveAsync(MetadataAddress, cancel).ConfigureAwait(false);
if (handlerResult != null && handlerResult.Configuration != null)
{
var handlerElapsedTime = TimeProvider.GetElapsedTime(beforeHandlerTimestamp);
TelemetryClient.LogConfigurationRetrievalDuration(
MetadataAddress,
handlerElapsedTime);// TODO new dimension for source
TelemetryConstants.Protocols.HandlerAsConfigurationSource,
handlerElapsedTime);

// Validate configuration from handler
if (_configValidator != null)
{
ConfigurationValidationResult result = _configValidator.Validate(cachedResult.Configuration);
ConfigurationValidationResult result = _configValidator.Validate(handlerResult.Configuration);
if (!result.Succeeded)
{
// Just log the error and proceed to fetch from endpoint
LogHelper.LogExceptionMessage(
new InvalidConfigurationException(
LogHelper.FormatInvariant(
LogMessages.IDX20810, // TODO new log message
LogMessages.IDX20812,
result.ErrorMessage)));

return false;
return ConfigurationEventHandlerResult<T>.NoResult;
}
}

// No validator configured, use configuration
TelemetryClient.IncrementConfigurationRefreshRequestCounter(
MetadataAddress,
TelemetryConstants.Protocols.FirstRefresh); // TODO new dimension for source

UpdateConfiguration(cachedResult.Configuration, cachedResult.RetrievalTime);
return true;
// No validator configured, return configuration
return handlerResult;
}
}
catch (Exception ex)
{
var handlerErrorElapsedTime = TimeProvider.GetElapsedTime(beforeHandlerTimestamp);
TelemetryClient.LogConfigurationRetrievalDuration(
MetadataAddress,
TelemetryConstants.Protocols.HandlerAsConfigurationSource,
handlerErrorElapsedTime,
ex); // TODO new dimension for source
ex);

// Log but don't fail - proceed to fetch from endpoint
// TODO check error
LogHelper.LogExceptionMessage(
new InvalidOperationException(
LogHelper.FormatInvariant(
"Failed to retrieve configuration from event handler. MetadataAddress: '{0}', Exception: '{1}'.",
LogMessages.IDX20811,
LogHelper.MarkAsNonPII(MetadataAddress ?? "null"),
ex),
ex));
}
#pragma warning restore CA1031 // Do not catch general exception types

return false;
return ConfigurationEventHandlerResult<T>.NoResult;
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,19 @@ private async Task<T> GetConfigurationWithBlockingAsync(CancellationToken cancel
if (ConfigurationEventHandler != null)
{
var configurationRetrieved = await HandleBeforeRetrieveAsync(cancel).ConfigureAwait(false);
if (configurationRetrieved)

// replicate the behavior of successful retrieval from endpoint
if (configurationRetrieved != null && configurationRetrieved.Configuration != null)
{
TelemetryForUpdateBlocking(TelemetryConstants.Protocols.HandlerAsConfigurationSource);

if (_refreshRequested)
_refreshRequested = false;

UpdateConfiguration(configurationRetrieved.Configuration, configurationRetrieved.RetrievalTime);

return _currentConfiguration;
}
}

// Don't use the individual CT here, this is a shared operation that shouldn't be affected by an individual's cancellation.
Expand All @@ -49,6 +60,7 @@ private async Task<T> GetConfigurationWithBlockingAsync(CancellationToken cancel
var elapsedTime = TimeProvider.GetElapsedTime(startTimestamp);
TelemetryClient.LogConfigurationRetrievalDuration(
MetadataAddress,
TelemetryConstants.Protocols.EndpointAsConfigurationSource,
elapsedTime);

if (_configValidator != null)
Expand All @@ -60,7 +72,7 @@ private async Task<T> GetConfigurationWithBlockingAsync(CancellationToken cancel

_lastRequestRefresh = TimeProvider.GetUtcNow().UtcDateTime;

TelemetryForUpdateBlocking();
TelemetryForUpdateBlocking(TelemetryConstants.Protocols.EndpointAsConfigurationSource);

if (_refreshRequested)
_refreshRequested = false;
Expand Down Expand Up @@ -90,6 +102,7 @@ private async Task<T> GetConfigurationWithBlockingAsync(CancellationToken cancel
TelemetryClient.IncrementConfigurationRefreshRequestCounter(
MetadataAddress,
TelemetryConstants.Protocols.FirstRefresh,
TelemetryConstants.Protocols.EndpointAsConfigurationSource,
ex);

throw LogHelper.LogExceptionMessage(
Expand All @@ -106,6 +119,7 @@ private async Task<T> GetConfigurationWithBlockingAsync(CancellationToken cancel

TelemetryClient.LogConfigurationRetrievalDuration(
MetadataAddress,
TelemetryConstants.Protocols.EndpointAsConfigurationSource,
elapsedTime,
ex);

Expand Down Expand Up @@ -147,7 +161,7 @@ private void RequestRefreshBlocking()
}
}

private void TelemetryForUpdateBlocking()
private void TelemetryForUpdateBlocking(string configurationSource)
{
string updateMode;

Expand All @@ -160,6 +174,7 @@ private void TelemetryForUpdateBlocking()
{
TelemetryClient.IncrementConfigurationRefreshRequestCounter(
MetadataAddress,
configurationSource,
updateMode);
}
#pragma warning disable CA1031 // Do not catch general exception types
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
const Microsoft.IdentityModel.Protocols.LogMessages.IDX20811 = "IDX20811: Failed to retrieve configuration from event handler. MetadataAddress: '{0}', Exception: '{1}'." -> string
const Microsoft.IdentityModel.Protocols.LogMessages.IDX20812 = "IDX20812: Failed to validate configuration retrieved via event handler. Exception: '{0}'." -> string
2 changes: 2 additions & 0 deletions src/Microsoft.IdentityModel.Protocols/LogMessages.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ internal static class LogMessages
internal const string IDX20808 = "IDX20808: Network error occurred. Status code: '{0}'. \nResponse content: '{1}'. \nAttempting to retrieve document again from: '{2}'.";
internal const string IDX20809 = "IDX20809: Unable to retrieve document from: '{0}'. Status code: '{1}'. \nResponse content: '{2}'.";
internal const string IDX20810 = "IDX20810: Configuration validation failed, see inner exception for more details. Exception: '{0}'.";
internal const string IDX20811 = "IDX20811: Failed to retrieve configuration from event handler. MetadataAddress: '{0}', Exception: '{1}'.";
internal const string IDX20812 = "IDX20812: Failed to validate configuration retrieved via event handler. Exception: '{0}'.";

#pragma warning restore 1591
}
Expand Down
14 changes: 14 additions & 0 deletions src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
const Microsoft.IdentityModel.Telemetry.TelemetryConstants.ConfigurationSourceTag = "ConfigurationSource" -> string
const Microsoft.IdentityModel.Telemetry.TelemetryConstants.Protocols.EndpointAsConfigurationSource = "MetadataEndpoint" -> string
const Microsoft.IdentityModel.Telemetry.TelemetryConstants.Protocols.HandlerAsConfigurationSource = "Handler" -> string
const Microsoft.IdentityModel.Telemetry.TelemetryConstants.Protocols.IrrelevantConfigurationSource = "IrrelevantForScenario" -> string
const Microsoft.IdentityModel.Tokens.AppContextSwitches.UseCapitalizedXMLTypeAttrSwitch = "Switch.Microsoft.IdentityModel.UseCapitalizedXMLTypeAttr" -> string
const Microsoft.IdentityModel.Tokens.LogMessages.IDX10278 = "IDX10278: Unable to retrieve configuration from authority: '{0}'. \nProceeding with token decryption in case the relevant properties have been set manually on the TokenValidationParameters. Exception caught: \n {1}. See https://aka.ms/validate-using-configuration-manager for additional information." -> string
Microsoft.IdentityModel.Telemetry.ITelemetryClient.IncrementConfigurationRefreshRequestCounter(string metadataAddress, string operationStatus, string configurationSource) -> void
Microsoft.IdentityModel.Telemetry.ITelemetryClient.IncrementConfigurationRefreshRequestCounter(string metadataAddress, string operationStatus, string configurationSource, System.Exception exception) -> void
Microsoft.IdentityModel.Telemetry.ITelemetryClient.LogBackgroundConfigurationRefreshFailure(string metadataAddress, string configurationSource, System.Exception exception) -> void
Microsoft.IdentityModel.Telemetry.ITelemetryClient.LogConfigurationRetrievalDuration(string metadataAddress, string configurationSource, System.TimeSpan operationDuration) -> void
Microsoft.IdentityModel.Telemetry.ITelemetryClient.LogConfigurationRetrievalDuration(string metadataAddress, string configurationSource, System.TimeSpan operationDuration, System.Exception exception) -> void
Microsoft.IdentityModel.Telemetry.TelemetryClient.IncrementConfigurationRefreshRequestCounter(string metadataAddress, string operationStatus, string configurationSource) -> void
Microsoft.IdentityModel.Telemetry.TelemetryClient.IncrementConfigurationRefreshRequestCounter(string metadataAddress, string operationStatus, string configurationSource, System.Exception exception) -> void
Microsoft.IdentityModel.Telemetry.TelemetryClient.LogBackgroundConfigurationRefreshFailure(string metadataAddress, string configurationSource, System.Exception exception) -> void
Microsoft.IdentityModel.Telemetry.TelemetryClient.LogConfigurationRetrievalDuration(string metadataAddress, string configurationSource, System.TimeSpan operationDuration) -> void
Microsoft.IdentityModel.Telemetry.TelemetryClient.LogConfigurationRetrievalDuration(string metadataAddress, string configurationSource, System.TimeSpan operationDuration, System.Exception exception) -> void
static Microsoft.IdentityModel.Tokens.AppContextSwitches.UseCapitalizedXMLTypeAttr.get -> bool
Loading