Skip to content

Commit

Permalink
MSAL logging levels now correlate with the AzureEventSourceListener
Browse files Browse the repository at this point in the history
… configured log level (Azure#44631)
  • Loading branch information
christothes authored and tejasm-microsoft committed Jul 22, 2024
1 parent 8fcb34a commit 458e91d
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 3 deletions.
1 change: 1 addition & 0 deletions sdk/identity/Azure.Identity/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
### Bugs Fixed

### Other Changes
- The logging level passed to MSAL now correlates to the log level configured on your configured `AzureEventSourceListener`. Previously, the log level was always set to `Microsoft.Identity.Client.LogLevel.Info`.

## 1.12.0 (2024-06-17)

Expand Down
56 changes: 55 additions & 1 deletion sdk/identity/Azure.Identity/src/AzureIdentityEventSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@
using System.Text;
using Azure.Core;
using Azure.Core.Diagnostics;
using Microsoft.IdentityModel.Abstractions;

namespace Azure.Identity
{
[EventSource(Name = EventSourceName)]
internal sealed class AzureIdentityEventSource : AzureEventSource
internal sealed class AzureIdentityEventSource : AzureEventSource, IIdentityLogger
{
private const string EventSourceName = "Azure-Identity";

Expand All @@ -26,6 +27,8 @@ internal sealed class AzureIdentityEventSource : AzureEventSource
private const int MsalLogInfoEvent = 8;
private const int MsalLogWarningEvent = 9;
private const int MsalLogErrorEvent = 10;
private const int MsalLogCriticalEvent = 23;
private const int MsalLogAlwaysEvent = 24;
private const int InteractiveAuthenticationThreadPoolExecutionEvent = 11;
private const int InteractiveAuthenticationInlineExecutionEvent = 12;
private const int DefaultAzureCredentialCredentialSelectedEvent = 13;
Expand All @@ -50,6 +53,45 @@ private AzureIdentityEventSource() : base(EventSourceName) { }

public static AzureIdentityEventSource Singleton { get; } = new AzureIdentityEventSource();

public bool IsEnabled(EventLogLevel eventLogLevel)
{
return eventLogLevel switch
{
EventLogLevel.Critical => IsEnabled(EventLevel.Critical, EventKeywords.All),
EventLogLevel.Error => IsEnabled(EventLevel.Error, EventKeywords.All),
EventLogLevel.Warning => IsEnabled(EventLevel.Warning, EventKeywords.All),
EventLogLevel.Informational => IsEnabled(EventLevel.Informational, EventKeywords.All),
EventLogLevel.Verbose => IsEnabled(EventLevel.Verbose, EventKeywords.All),
EventLogLevel.LogAlways => IsEnabled(EventLevel.LogAlways, EventKeywords.All),
_ => false,
};
}

public void Log(LogEntry entry)
{
switch (entry.EventLogLevel)
{
case EventLogLevel.Critical when IsEnabled(EventLevel.Critical, EventKeywords.All):
LogMsalCritical(entry.Message);
break;
case EventLogLevel.Error when IsEnabled(EventLevel.Error, EventKeywords.All):
LogMsalError(entry.Message);
break;
case EventLogLevel.Warning when IsEnabled(EventLevel.Warning, EventKeywords.All):
LogMsalWarning(entry.Message);
break;
case EventLogLevel.Informational when IsEnabled(EventLevel.Informational, EventKeywords.All):
LogMsalInformational(entry.Message);
break;
case EventLogLevel.Verbose when IsEnabled(EventLevel.Verbose, EventKeywords.All):
LogMsalVerbose(entry.Message);
break;
case EventLogLevel.LogAlways when IsEnabled(EventLevel.LogAlways, EventKeywords.All):
LogMsalAlways(entry.Message);
break;
}
}

[NonEvent]
public void GetToken(string method, TokenRequestContext context)
{
Expand Down Expand Up @@ -197,6 +239,12 @@ public void LogMsal(Microsoft.Identity.Client.LogLevel level, string message)
}
}

[Event(MsalLogCriticalEvent, Level = EventLevel.Critical, Message = "{0}")]
public void LogMsalCritical(string message)
{
WriteEvent(MsalLogCriticalEvent, message);
}

[Event(MsalLogErrorEvent, Level = EventLevel.Error, Message = "{0}")]
public void LogMsalError(string message)
{
Expand All @@ -221,6 +269,12 @@ public void LogMsalVerbose(string message)
WriteEvent(MsalLogVerboseEvent, message);
}

[Event(MsalLogAlwaysEvent, Level = EventLevel.LogAlways, Message = "{0}")]
public void LogMsalAlways(string message)
{
WriteEvent(MsalLogAlwaysEvent, message);
}

[NonEvent]
private static string FormatStringArray(string[] array)
{
Expand Down
2 changes: 1 addition & 1 deletion sdk/identity/Azure.Identity/src/MsalConfidentialClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ protected virtual async ValueTask<IConfidentialClientApplication> CreateClientCo

ConfidentialClientApplicationBuilder confClientBuilder = ConfidentialClientApplicationBuilder.Create(ClientId)
.WithHttpClientFactory(new HttpPipelineClientFactory(Pipeline.HttpPipeline))
.WithLogging(LogMsal, enablePiiLogging: IsSupportLoggingEnabled);
.WithLogging(AzureIdentityEventSource.Singleton, enablePiiLogging: IsSupportLoggingEnabled);

// Special case for using appTokenProviderCallback, authority validation and instance metadata discovery should be disabled since we're not calling the STS
// The authority matches the one configured in the CredentialOptions.
Expand Down
2 changes: 1 addition & 1 deletion sdk/identity/Azure.Identity/src/MsalPublicClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ protected virtual ValueTask<IPublicClientApplication> CreateClientCoreAsync(bool
.Create(ClientId)
.WithAuthority(authorityUri)
.WithHttpClientFactory(new HttpPipelineClientFactory(Pipeline.HttpPipeline))
.WithLogging(LogMsal, enablePiiLogging: IsSupportLoggingEnabled);
.WithLogging(AzureIdentityEventSource.Singleton, enablePiiLogging: IsSupportLoggingEnabled);

if (!string.IsNullOrEmpty(RedirectUrl))
{
Expand Down
49 changes: 49 additions & 0 deletions sdk/identity/Azure.Identity/tests/CredentialTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,55 @@ public async Task RespectsIsSupportLoggingEnabled([Values(true, false)] bool isS
Assert.True(_listener.EventData.Any(d => d.Payload.Any(p => p.ToString().StartsWith($"{expectedPrefix} MSAL"))));
}

[Test]
[TestCase(EventLevel.Informational)]
[TestCase(EventLevel.Verbose)]
public async Task ListenerEventLevelControlsMsalLogLevel(EventLevel eventLevel)
{
using var _listener = new TestEventListener();
_listener.EnableEvents(AzureIdentityEventSource.Singleton, eventLevel);

var token = Guid.NewGuid().ToString();
TransportConfig transportConfig = new()
{
TokenFactory = req => token
};
var factory = MockTokenTransportFactory(transportConfig);
var mockTransport = new MockTransport(factory);

var config = new CommonCredentialTestConfig()
{
TransportConfig = transportConfig,
Transport = mockTransport,
TenantId = TenantId,
IsUnsafeSupportLoggingEnabled = true
};
var credential = GetTokenCredential(config);
if (!CredentialTestHelpers.IsMsalCredential(credential))
{
Assert.Ignore($"{credential.GetType().Name} is not an MSAL credential.");
}
transportConfig.IsPubClient = CredentialTestHelpers.IsCredentialTypePubClient(credential);
AccessToken actualToken = await credential.GetTokenAsync(new TokenRequestContext(MockScopes.Default, null), default);

Assert.AreEqual(token, actualToken.Token);

Assert.True(_listener.EventData.Any(d => d.Level == EventLevel.Informational && d.EventName == "LogMsalInformational"));

switch (eventLevel)
{
case EventLevel.Informational:
Assert.False(_listener.EventData.Any(d => d.Level == EventLevel.Verbose && d.EventName == "LogMsalVerbose"));
break;
case EventLevel.Verbose:
Assert.True(_listener.EventData.Any(d => d.Level == EventLevel.Verbose && d.EventName == "LogMsalVerbose"));
break;
default:
Assert.Fail("Unexpected event level");
break;
}
}

[Test]
[NonParallelizable]
public async Task DisableInstanceMetadataDiscovery([Values(true, false)] bool disable)
Expand Down

0 comments on commit 458e91d

Please sign in to comment.