Skip to content

Instantly share code, notes, and snippets.

@bgavrilMS
Created March 29, 2022 21:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bgavrilMS/067a913480ae3e96aea0ca0407f82521 to your computer and use it in GitHub Desktop.
Save bgavrilMS/067a913480ae3e96aea0ca0407f82521 to your computer and use it in GitHub Desktop.
Logging prototype 2
using System;
using System.Diagnostics.Tracing;
namespace ConsoleApp2.p4
{
/// <summary>
/// With Global PII setting.
/// </summary>
public class Prototype4
{
public static void Prototype()
{
// App developer configures logger
IIdentityLogger logger = new ConsoleLoggerImpl(EventLevel.Verbose);
MsalLogger msalInternalLogging =
Adapter.FromIIdentityLogger(logger, new RequestContext() { CorrelationId = "correlationId", UsePii = true });
WithLogging(LogCallback callbacl, LogLevel level, bool capturePii);
WithLogging(LogCallback callbacl, Func<LogLevel, bool> isLoggingEnabled, bool capturePii);
WithLogging(IIdentityLogger logger, bool capturePii);
WithLogging(IIdentityLogger logger, ILogScrubber scrubber);
// How to adapt IIdentityLoggger to MsalLogger?
// Now MSAL outputs some log messages
//LogHelper msalInternalLogging = new LogHelper(logger, "activity_id");
msalInternalLogging.Log(LogLevel.Info, "Info message no pii", "Info message with pii");
//msalInternalLogging.Log(LogLevel.Info, "Info message2 no pii");
//msalInternalLogging.Log(EventLevel.Verbose, "Verobse message no pii", "Verbose with pii");
//msalInternalLogging.Log(EventLevel.Verbose, "Verobse message2 no pii");
//msalInternalLogging.Log(EventLevel.LogAlways, "LogAlways message no pii", "LogAlways message with pii");
//msalInternalLogging.Log(EventLevel.LogAlways, "LogAlways message2 no pii");
//msalInternalLogging.Log(EventLevel.Error, "Error message no pii", "Error message with pii");
//msalInternalLogging.Log(EventLevel.Error, "Error message2 no pii");
if (msalInternalLogging.IsLoggingEnabled(LogLevel.Verbose))
{
msalInternalLogging.Log(LogLevel.Verbose, GetExpensiveLogMessage(), null);
}
}
private static string GetExpensiveLogMessage()
{
Console.WriteLine("EXPENSIVE LOG MESSAGE COMPUTED. Is this expected?");
return "This is an expensive verbose message";
}
}
public class MsalLogger
{
private readonly LogCallback _loggingCallback;
private readonly bool _isPiiEnabled;
private readonly Func<LogLevel, bool> _isEnabled;
//private readonly LogLevel _minLogLevel;
public MsalLogger(LogCallback loggingCallback, bool isPiiEnabled, LogLevel logLevel)
{
this._loggingCallback = loggingCallback;
this._isPiiEnabled = isPiiEnabled;
//this._minLogLevel = logLevel;
_isEnabled = (level) => level <= logLevel;
}
public MsalLogger(LogCallback loggingCallback, bool isPiiEnabled, Func<LogLevel, bool> isEnabled)
{
this._loggingCallback = loggingCallback;
this._isPiiEnabled = isPiiEnabled;
this._isEnabled = isEnabled;
}
public void Log(LogLevel logLevel, string messageWithPii, string messageScrubbed)
{
if (IsLoggingEnabled(logLevel))
{
bool messageWithPiiExists = !string.IsNullOrWhiteSpace(messageWithPii);
// If we have a message with PII, and PII logging is enabled, use the PII message, else use the scrubbed message.
bool isLoggingPii = messageWithPiiExists && _isPiiEnabled;
string messageToLog = isLoggingPii ? messageWithPii : messageScrubbed;
_loggingCallback.Invoke(logLevel, messageWithPii, isLoggingPii);
}
}
public bool IsLoggingEnabled(LogLevel logLevel)
{
//return _loggingCallback != null && logLevel <= _minLogLevel;
return _loggingCallback != null && _isEnabled(logLevel);
}
}
public class RequestContext
{
public string CorrelationId;
public bool UsePii;
}
public class Adapter
{
public static MsalLogger FromIIdentityLogger(IIdentityLogger identityLogger, RequestContext context)
{
LogCallback callback = (lvl, msg, pii) =>
{
var eventLevel = GetLevel(lvl);
if (identityLogger.IsEnabled(eventLevel))
{
LogEntry entry = new LogEntry()
{
EventLevel = GetLevel(lvl),
CorrelationId = context.CorrelationId,
Message = msg
};
identityLogger.Log(entry);
}
};
Func<LogLevel, bool> isEnabledFunc = (level) =>
{
return identityLogger.IsEnabled(GetLevel(level));
};
MsalLogger msalLogger = new MsalLogger(callback, context.UsePii, isEnabledFunc);
return msalLogger;
}
private static EventLevel GetLevel(LogLevel logLevel)
{
switch (logLevel)
{
case LogLevel.Verbose:
return EventLevel.Verbose;
case LogLevel.Info:
return EventLevel.Informational;
case LogLevel.Warning:
return EventLevel.Warning;
case LogLevel.Error:
return EventLevel.Error;
case LogLevel.Always:
return EventLevel.LogAlways;
default:
return EventLevel.Warning;
}
}
//private static LogLevel GetLevel(EventLevel eventLevel)
//{
// switch (eventLevel)
// {
// case EventLevel.LogAlways:
// return LogLevel.Always;
// case EventLevel.Critical:
// return LogLevel.Error;
// case EventLevel.Error:
// return LogLevel.Error;
// case EventLevel.Warning:
// return LogLevel.Warning;
// case EventLevel.Informational:
// return LogLevel.Info;
// case EventLevel.Verbose:
// return LogLevel.Verbose;
// default:
// break;
// }
//}
}
public delegate void LogCallback(LogLevel level, string message, bool containsPii);
public enum LogLevel
{
/// <summary>
/// Includes logs of important health metrics to help with diagnostics of MSAL operations.
/// </summary>
Always = -1,
/// <summary>
/// Includes logs when something has gone wrong and an error was generated. Used for debugging and identifying problems.
/// </summary>
Error = 0,
/// <summary>
/// Includes logs in scenarios when there hasn't necessarily been an error or failure, but are intended for diagnostics and pinpointing problems.
/// </summary>
Warning = 1,
/// <summary>
/// Default. Includes logs of general events intended for informational purposes, not necessarily intended for debugging.
/// </summary>
Info = 2,
/// <summary>
/// Includes logs of the full details of library behavior.
/// </summary>
Verbose = 3
}
//public class LogHelper
//{
// private readonly IIdentityLogger _logger;
// private readonly string _correlationId;
// public const string MsalVersion = "1.0.0";
// public static bool GlobalPiiSetting = true;
// public LogHelper(IIdentityLogger logger, string correlationId)
// {
// _logger = logger;
// _correlationId = correlationId;
// }
// public bool IsEnabled(EventLevel level)
// {
// return _logger.IsEnabled(level);
// }
// public void Log(EventLevel level, string messageNoPii)
// {
// if (IsEnabled(level))
// {
// _logger.Log(new LogEntry()
// {
// EventLevel = level,
// Message = messageNoPii,
// });
// }
// }
// public void Log(EventLevel level, string messageNoPii, string messageWithPii)
// {
// if (IsEnabled(level))
// {
// string messageToLog = (GlobalPiiSetting == true) ? messageWithPii : messageNoPii;
// _logger.Log(new LogEntry()
// {
// EventLevel = level,
// Message = messageToLog,
// CorrelationId = _correlationId,
// });
// }
// }
//}
public class ConsoleLoggerImpl : IIdentityLogger
{
private readonly EventLevel _minLevel;
public ConsoleLoggerImpl(EventLevel minLevel)
{
_minLevel = minLevel;
}
public bool IsEnabled(EventLevel level)
{
return (level <= _minLevel);
}
public void Log(LogEntry entry)
{
Console.WriteLine($"{entry.EventLevel} {entry.Message} ");
}
}
public interface IIdentityLogger // part of new package
{
bool IsEnabled(EventLevel level);
/// <summary>
/// Writes a log entry.
/// </summary>
/// <param name="entry">Defines a structured message to be logged at the provided <see cref="LogEntry.EventLevel"/>.</param>
void Log(LogEntry entry);
}
/// </summary>
public class LogEntry // part of new package
{
/// <summary>
/// Defines the <see cref="EventLevel"/>.
/// </summary>
public EventLevel EventLevel { get; set; }
/// <summary>
/// Message to be logged.
/// </summary>
public string Message { get; set; }
/// <summary>
/// A unique identifier for a request that can help with diagnostics across components.
/// </summary>
public string CorrelationId { get; set; }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment