Skip to content

Commit 7476fcb

Browse files
committed
Provide support to Log using ILogger
1 parent edd8166 commit 7476fcb

File tree

18 files changed

+1656
-64
lines changed

18 files changed

+1656
-64
lines changed

src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.ValidateToken.cs

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
using System.Threading.Tasks;
1010
using Microsoft.IdentityModel.Abstractions;
1111
using Microsoft.IdentityModel.Logging;
12-
using Microsoft.IdentityModel.Tokens;
1312
using Microsoft.IdentityModel.Telemetry;
13+
using Microsoft.IdentityModel.Tokens;
1414
using TokenLogMessages = Microsoft.IdentityModel.Tokens.LogMessages;
1515

1616
namespace Microsoft.IdentityModel.JsonWebTokens
@@ -444,14 +444,36 @@ public override async Task<TokenValidationResult> ValidateTokenAsync(string toke
444444
public override async Task<TokenValidationResult> ValidateTokenAsync(SecurityToken token, TokenValidationParameters validationParameters)
445445
{
446446
if (token == null)
447-
throw LogHelper.LogArgumentNullException(nameof(token));
447+
{
448+
return new TokenValidationResult
449+
{
450+
Exception = LogHelper.LogArgumentNullException(nameof(token)),
451+
IsValid = false
452+
};
453+
}
448454

449455
if (validationParameters == null)
450-
return new TokenValidationResult { Exception = LogHelper.LogArgumentNullException(nameof(validationParameters)), IsValid = false };
456+
return new TokenValidationResult
457+
{
458+
Exception = LogHelper.LogArgumentNullException(nameof(validationParameters)),
459+
IsValid = false
460+
};
451461

452462
var jwt = token as JsonWebToken;
453463
if (jwt == null)
454-
return new TokenValidationResult { Exception = LogHelper.LogArgumentException<ArgumentException>(nameof(token), $"{nameof(token)} must be a {nameof(JsonWebToken)}."), IsValid = false };
464+
{
465+
return new TokenValidationResult
466+
{
467+
Exception = LogHelper.LogExceptionMessage(
468+
new ArgumentException(
469+
$"{nameof(token)} must be a {nameof(JsonWebToken)}.",
470+
nameof(token)
471+
),
472+
TokenValidationParametersExtensions.GetCallContext(validationParameters)
473+
),
474+
IsValid = false
475+
};
476+
}
455477

456478
try
457479
{
@@ -480,6 +502,7 @@ internal async ValueTask<TokenValidationResult> ValidateTokenAsync(
480502
TokenValidationParameters validationParameters)
481503
{
482504
BaseConfiguration currentConfiguration = null;
505+
483506
if (validationParameters.ConfigurationManager != null)
484507
{
485508
try
@@ -493,7 +516,11 @@ internal async ValueTask<TokenValidationResult> ValidateTokenAsync(
493516
// The exception is not re-thrown as the TokenValidationParameters may have the issuer and signing key set
494517
// directly on them, allowing the library to continue with token validation.
495518
if (LogHelper.IsEnabled(EventLogLevel.Warning))
496-
LogHelper.LogWarning(LogHelper.FormatInvariant(TokenLogMessages.IDX10261, validationParameters.ConfigurationManager.MetadataAddress, ex.ToString()));
519+
LogHelper.LogWarning(
520+
LogHelper.FormatInvariant(
521+
TokenLogMessages.IDX10261,
522+
validationParameters.ConfigurationManager.MetadataAddress,
523+
ex.ToString()));
497524
}
498525
}
499526

src/Microsoft.IdentityModel.JsonWebTokens/JsonWebTokenHandler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
namespace Microsoft.IdentityModel.JsonWebTokens
1616
{
1717
/// <summary>
18-
/// A <see cref="SecurityTokenHandler"/> designed for creating and validating JSON Web Tokens.
18+
/// A <see cref="TokenHandler"/> designed for creating and validating JSON Web Tokens.
1919
/// See: <see href="https://datatracker.ietf.org/doc/html/rfc7519"/> and <see href="https://www.rfc-editor.org/info/rfc7515"/>.
2020
/// </summary>
2121
public partial class JsonWebTokenHandler : TokenHandler
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
static Microsoft.IdentityModel.Logging.LogHelper.IsEnabled(Microsoft.Extensions.Logging.LogLevel logLevel, Microsoft.IdentityModel.Logging.LoggerContext loggerContext) -> bool
2+
static Microsoft.IdentityModel.Logging.LogHelper.IsEnabled(Microsoft.IdentityModel.Abstractions.EventLogLevel level, Microsoft.Extensions.Logging.LogLevel logLevel, Microsoft.IdentityModel.Logging.LoggerContext loggerContext) -> bool

src/Microsoft.IdentityModel.Logging/LogHelper.cs

Lines changed: 215 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Diagnostics.Tracing;
77
using System.Globalization;
88
using System.Linq;
9+
using Microsoft.Extensions.Logging;
910
using Microsoft.IdentityModel.Abstractions;
1011

1112
namespace Microsoft.IdentityModel.Logging
@@ -42,6 +43,17 @@ internal static bool HeaderWritten
4243
set { _isHeaderWritten = value; }
4344
}
4445

46+
/// <summary>
47+
/// Gets a boolean indicating whether logging is enabled at the specified LogLevel.
48+
/// </summary>
49+
/// <param name="logLevel">The log level</param>
50+
/// <param name="loggerContext">A <see cref="LoggerContext"/> that contains logging control including <see cref="ILogger"/>.</param>
51+
/// <returns><see langword="true"/> if logging is enabled at the specified level; otherwise, <see langword="false"/>.</returns>
52+
internal static bool IsEnabled(LogLevel logLevel, LoggerContext loggerContext)
53+
{
54+
return loggerContext?.Logger?.IsEnabled(logLevel) ?? false;
55+
}
56+
4557
/// <summary>
4658
/// Gets whether logging is enabled at the specified <see cref="EventLogLevel"/>."/>
4759
/// </summary>
@@ -269,7 +281,38 @@ public static Exception LogExceptionMessage(EventLevel eventLevel, Exception exc
269281

270282
EventLogLevel eventLogLevel = EventLevelToEventLogLevel(eventLevel);
271283
if (Logger.IsEnabled(eventLogLevel))
272-
Logger.Log(WriteEntry(eventLogLevel, exception.InnerException, exception.Message, null));
284+
Logger.Log(WriteEntry(eventLogLevel, exception.InnerException, exception.Message));
285+
286+
return exception;
287+
}
288+
289+
/// <summary>
290+
/// Logs an exception using the listeners that have been enabled.
291+
/// </summary>
292+
/// <param name="exception">The exception to log.</param>
293+
/// <param name="loggerContext">The <see cref="LoggerContext"/> contains information useful for logging and debugging.</param>
294+
public static Exception LogExceptionMessage(Exception exception, LoggerContext loggerContext)
295+
{
296+
if (exception == null)
297+
return null;
298+
299+
LogExceptionMessage(exception);
300+
301+
if (loggerContext?.Logger == null)
302+
return exception;
303+
304+
if (!loggerContext.Logger.IsEnabled(LogLevel.Error))
305+
return exception;
306+
307+
LogEntry entry = WriteEntry(
308+
EventLogLevel.Error,
309+
exception.InnerException,
310+
exception.Message,
311+
loggerContext.CorrelationId ?? loggerContext.ActivityId.ToString(),
312+
exception.Message,
313+
null);
314+
315+
Log(entry, loggerContext.Logger);
273316

274317
return exception;
275318
}
@@ -285,7 +328,33 @@ public static void LogInformation(string message, params object[] args)
285328
IdentityModelEventSource.Logger.WriteInformation(message, args);
286329

287330
if (Logger.IsEnabled(EventLogLevel.Informational))
288-
Logger.Log(WriteEntry(EventLogLevel.Informational, null, message, args));
331+
Logger.Log(WriteEntry(EventLogLevel.Informational, null, message, null, args));
332+
}
333+
334+
/// <summary>
335+
/// Logs at the information level to the listeners that have been enabled.
336+
/// </summary>
337+
/// <param name="message">The log message.</param>
338+
/// <param name="loggerContext">A <see cref="LoggerContext"/> that contains logging control including <see cref="ILogger"/>.</param>
339+
/// <param name="args">An object array that contains zero or more objects to format.</param>
340+
public static void LogInformation(string message, LoggerContext loggerContext, params object[] args)
341+
{
342+
LogInformation(message, args);
343+
344+
if (loggerContext?.Logger == null)
345+
return;
346+
347+
if (!loggerContext.Logger.IsEnabled(LogLevel.Information))
348+
return;
349+
350+
LogEntry entry = WriteEntry(
351+
EventLevelToEventLogLevel(EventLevel.Informational),
352+
null,
353+
message,
354+
loggerContext.CorrelationId ?? loggerContext.ActivityId.ToString(),
355+
null);
356+
357+
Log(entry, loggerContext.Logger);
289358
}
290359

291360
/// <summary>
@@ -299,7 +368,33 @@ public static void LogVerbose(string message, params object[] args)
299368
IdentityModelEventSource.Logger.WriteVerbose(message, args);
300369

301370
if (Logger.IsEnabled(EventLogLevel.Verbose))
302-
Logger.Log(WriteEntry(EventLogLevel.Verbose, null, message, args));
371+
Logger.Log(WriteEntry(EventLogLevel.Verbose, null, message, null, args));
372+
}
373+
374+
/// <summary>
375+
/// Logs at the verbose level to the listeners that have been enabled.
376+
/// </summary>
377+
/// <param name="message">The log message.</param>
378+
/// <param name="loggerContext">A <see cref="LoggerContext"/> that contains logging control including <see cref="ILogger"/>.</param>
379+
/// <param name="args">An object array that contains zero or more objects to format.</param>
380+
public static void LogVerbose(string message, LoggerContext loggerContext, params object[] args)
381+
{
382+
LogVerbose(message, args);
383+
384+
if (loggerContext?.Logger == null)
385+
return;
386+
387+
if (!loggerContext.Logger.IsEnabled(LogLevel.Debug))
388+
return;
389+
390+
LogEntry entry = WriteEntry(
391+
EventLogLevel.Verbose,
392+
null,
393+
message,
394+
loggerContext.CorrelationId ?? loggerContext.ActivityId.ToString(),
395+
null);
396+
397+
Log(entry, loggerContext.Logger);
303398
}
304399

305400
/// <summary>
@@ -313,7 +408,43 @@ public static void LogWarning(string message, params object[] args)
313408
IdentityModelEventSource.Logger.WriteWarning(message, args);
314409

315410
if (Logger.IsEnabled(EventLogLevel.Warning))
316-
Logger.Log(WriteEntry(EventLogLevel.Warning, null, message, args));
411+
Logger.Log(WriteEntry(EventLogLevel.Warning, null, message, null, args));
412+
}
413+
414+
/// <summary>
415+
/// Logs at the warning level to the listeners that have been enabled.
416+
/// </summary>
417+
/// <param name="message">The log message.</param>
418+
/// <param name="loggerContext">A <see cref="LoggerContext"/> that contains logging control including <see cref="ILogger"/>.</param>
419+
public static void LogWarning(string message, LoggerContext loggerContext)
420+
{
421+
LogWarning(message, loggerContext, null);
422+
}
423+
424+
/// <summary>
425+
/// Logs at the warning level to the listeners that have been enabled.
426+
/// </summary>
427+
/// <param name="message">The log message.</param>
428+
/// <param name="loggerContext">A <see cref="LoggerContext"/> that contains logging control including <see cref="ILogger"/>.</param>
429+
/// <param name="args">An object array that contains zero or more objects to format.</param>
430+
public static void LogWarning(string message, LoggerContext loggerContext, params object[] args)
431+
{
432+
LogWarning(message, args);
433+
434+
if (loggerContext?.Logger == null)
435+
return;
436+
437+
if (!loggerContext.Logger.IsEnabled(LogLevel.Warning))
438+
return;
439+
440+
LogEntry entry = WriteEntry(
441+
EventLogLevel.Warning,
442+
null,
443+
message,
444+
loggerContext.CorrelationId ?? loggerContext.ActivityId.ToString(),
445+
null);
446+
447+
Log(entry, loggerContext.Logger);
317448
}
318449

319450
/// <summary>
@@ -337,7 +468,7 @@ public static void LogWarning(string message, params object[] args)
337468

338469
EventLogLevel eventLogLevel = EventLevelToEventLogLevel(eventLevel);
339470
if (Logger.IsEnabled(eventLogLevel))
340-
Logger.Log(WriteEntry(eventLogLevel, innerException, message, null));
471+
Logger.Log(WriteEntry(eventLogLevel, innerException, message));
341472

342473
if (innerException != null)
343474
{
@@ -487,7 +618,29 @@ public static object MarkAsUnsafeSecurityArtifact(object arg, Func<object, strin
487618
/// <param name="innerException"><see cref="Exception"/></param>
488619
/// <param name="message">The log message.</param>
489620
/// <param name="args">An object array that contains zero or more objects to format.</param>
490-
private static LogEntry WriteEntry(EventLogLevel eventLogLevel, Exception innerException, string message, params object[] args)
621+
private static LogEntry WriteEntry(
622+
EventLogLevel eventLogLevel,
623+
Exception innerException,
624+
string message,
625+
params object[] args)
626+
{
627+
return WriteEntry(eventLogLevel, innerException, message, (string)null, args);
628+
}
629+
630+
/// <summary>
631+
/// Creates a <see cref="LogEntry"/> by using the provided event level, exception argument, string argument and arguments list.
632+
/// </summary>
633+
/// <param name="eventLogLevel"><see cref="EventLogLevel"/></param>
634+
/// <param name="innerException"><see cref="Exception"/></param>
635+
/// <param name="message">The log message.</param>
636+
/// <param name="correlationId">The CorrelationId is set by caller to coordinate logs between services.</param>
637+
/// <param name="args">An object array that contains zero or more objects to format.</param>
638+
private static LogEntry WriteEntry(
639+
EventLogLevel eventLogLevel,
640+
Exception innerException,
641+
string message,
642+
string correlationId,
643+
params object[] args)
491644
{
492645
if (string.IsNullOrEmpty(message))
493646
return null;
@@ -505,23 +658,72 @@ private static LogEntry WriteEntry(EventLogLevel eventLogLevel, Exception innerE
505658

506659
LogEntry entry = new LogEntry();
507660
entry.EventLogLevel = eventLogLevel;
661+
entry.CorrelationId = correlationId;
508662

509663
// Prefix header (library version, DateTime, whether PII is ON/OFF) to the first message logged by Wilson.
510664
if (!_isHeaderWritten)
511665
{
512-
string headerMessage = string.Format(CultureInfo.InvariantCulture, "Microsoft.IdentityModel Version: {0}. Date {1}. {2}",
513-
typeof(IdentityModelEventSource).Assembly.GetName().Version.ToString(),
514-
DateTime.UtcNow,
515-
IdentityModelEventSource.ShowPII ? _piiOnLogMessage : _piiOffLogMessage);
516-
517-
entry.Message = headerMessage + Environment.NewLine + message;
666+
entry.Message = (correlationId == null) ?
667+
string.Format(
668+
CultureInfo.InvariantCulture,
669+
"Microsoft.IdentityModel Version: {0}. Date {1}. {2} Message: {3}",
670+
typeof(IdentityModelEventSource).Assembly.GetName().Version.ToString(),
671+
DateTime.UtcNow,
672+
IdentityModelEventSource.ShowPII ? _piiOnLogMessage : _piiOffLogMessage,
673+
Environment.NewLine + message) :
674+
string.Format(
675+
CultureInfo.InvariantCulture,
676+
"Microsoft.IdentityModel Version: {0}. Date {1}. {2} Message: {3}, CorrelationId: {4}.",
677+
typeof(IdentityModelEventSource).Assembly.GetName().Version.ToString(),
678+
DateTime.UtcNow,
679+
IdentityModelEventSource.ShowPII ? _piiOnLogMessage : _piiOffLogMessage,
680+
Environment.NewLine + message,
681+
correlationId);
518682

519683
_isHeaderWritten = true;
520684
}
521685
else
522-
entry.Message = message;
686+
entry.Message = (correlationId == null) ?
687+
message :
688+
string.Format(CultureInfo.InvariantCulture, "{0}, CorrelationId: {1}.", message, correlationId);
523689

524690
return entry;
525691
}
692+
693+
private static void Log(LogEntry entry, ILogger logger)
694+
{
695+
if (entry != null)
696+
{
697+
switch (entry.EventLogLevel)
698+
{
699+
case EventLogLevel.Critical:
700+
logger.LogCritical(entry.Message);
701+
break;
702+
703+
case EventLogLevel.Error:
704+
logger.LogError(entry.Message);
705+
break;
706+
707+
case EventLogLevel.Warning:
708+
logger.LogWarning(entry.Message);
709+
break;
710+
711+
case EventLogLevel.Informational:
712+
logger.LogInformation(entry.Message);
713+
break;
714+
715+
case EventLogLevel.Verbose:
716+
logger.LogDebug(entry.Message);
717+
break;
718+
719+
case EventLogLevel.LogAlways:
720+
logger.LogTrace(entry.Message);
721+
break;
722+
723+
default:
724+
break;
725+
}
726+
}
727+
}
526728
}
527729
}

0 commit comments

Comments
 (0)