/// <summary> /// Allocates object[]-array for <see cref="LogEventInfo.Parameters"/> after checking /// for mismatch between Microsoft Extension Logging and NLog Message Template Parser /// </summary> /// <remarks> /// Cannot trust the parameters received from Microsoft Extension Logging, as extra parameters can be injected /// </remarks> private static void CaptureLogEventInfoParameters(LogEventInfo logEvent, NLogMessageParameterList messageParameters, MessageTemplateParameters messageTemplateParameters) { if (messageTemplateParameters.IsPositional) { logEvent.Parameters = CreatePositionalLogEventInfoParameters(messageParameters, messageTemplateParameters, out var extraProperties); if (extraProperties?.Count > 0) { CaptureMessagePropertiesList(logEvent, extraProperties); } } else if (!AllParameterCorrectlyPositionalMapped(messageParameters, messageTemplateParameters)) { // Resolves mismatch between the input from Microsoft Extension Logging TState and NLog Message Template Parser logEvent.Parameters = CreateStructuredLogEventInfoParameters(messageParameters, messageTemplateParameters, out var extraProperties); if (extraProperties?.Count > 0) { CaptureMessagePropertiesList(logEvent, extraProperties); } } else { // Everything is mapped correctly, inject messageParameters directly as params-array var paramsArray = new object[messageTemplateParameters.Count]; for (int i = 0; i < paramsArray.Length; ++i) { paramsArray[i] = messageParameters[i].Value; } logEvent.Parameters = paramsArray; } }
/// <summary> /// Checks if the already parsed input message-parameters must be sent through /// the NLog MessageTemplate Parser for proper handling of message-template syntax. /// </summary> /// <remarks> /// Using the NLog MesageTemplate Parser will hurt performance: 1 x Microsoft Parser - 2 x NLog Parser - 1 x NLog Formatter /// </remarks> private LogEventInfo TryParseLogEventInfo(LogLevel nLogLogLevel, NLogMessageParameterList messageParameters) { if (messageParameters?.OriginalMessage != null && (messageParameters.HasComplexParameters || (_options.ParseMessageTemplates && messageParameters.Count > 0))) { // NLog MessageTemplate Parser must be used var eventInfo = new LogEventInfo(nLogLogLevel, _logger.Name, null, messageParameters.OriginalMessage as string, _singleItemArray); var messagetTemplateParameters = eventInfo.MessageTemplateParameters; // Forces parsing of OriginalMessage if (messagetTemplateParameters.Count > 0) { // We have parsed the message and found parameters, now we need to do the parameter mapping eventInfo.Parameters = CreateLogEventInfoParameters(messageParameters, messagetTemplateParameters, out var extraProperties); if (extraProperties?.Count > 0) { // Need to harvest additional parameters foreach (var property in extraProperties) { eventInfo.Properties[property.Name] = property.Value; } } return(eventInfo); } return(null); // Parsing not possible } return(null); // Parsing not needed }
private static object[] CreateStructuredLogEventInfoParameters(NLogMessageParameterList messageParameters, MessageTemplateParameters messageTemplateParameters, out List <KeyValuePair <string, object> > extraProperties) { extraProperties = null; var paramsArray = new object[messageTemplateParameters.Count]; int startPos = 0; int messageParameterCount = messageParameters.Count; for (int i = 0; i < messageParameterCount; ++i) { var propertyName = messageParameters[i].Name; bool extraProperty = true; for (int j = startPos; j < messageTemplateParameters.Count; ++j) { if (propertyName.Equals(messageTemplateParameters[j].Name, StringComparison.Ordinal)) { extraProperty = false; paramsArray[j] = messageParameters[i].Value; if (startPos == j) { startPos++; } break; } } if (extraProperty) { extraProperties = AddExtraProperty(extraProperties, messageParameters[i]); } } return(paramsArray); }
private static object[] CreatePositionalLogEventInfoParameters(NLogMessageParameterList messageParameters, MessageTemplateParameters messageTemplateParameters, out List <KeyValuePair <string, object> > extraProperties) { extraProperties = null; var maxIndex = FindMaxIndex(messageTemplateParameters); object[] paramsArray = null; int messageParameterCount = messageParameters.Count; for (int i = 0; i < messageParameterCount; ++i) { // First positional name is the startPos if (char.IsDigit(messageParameters[i].Name[0]) && paramsArray == null) { paramsArray = new object[maxIndex + 1]; for (int j = 0; j <= maxIndex; ++j) { if (i + j < messageParameterCount) { paramsArray[j] = messageParameters[i + j].Value; } } i += maxIndex; } else { extraProperties = AddExtraProperty(extraProperties, messageParameters[i]); } } return(paramsArray ?? new object[maxIndex + 1]); }
public void Log <TState>(Microsoft.Extensions.Logging.LogLevel logLevel, EventId eventId, TState state, Exception exception, Func <TState, Exception, string> formatter) { var nLogLogLevel = ConvertLogLevel(logLevel); if (!IsEnabled(nLogLogLevel)) { return; } if (formatter == null) { throw new ArgumentNullException(nameof(formatter)); } var messageParameters = NLogMessageParameterList.TryParse(_options.CaptureMessageTemplates ? state as IReadOnlyList <KeyValuePair <string, object> > : null); LogEventInfo eventInfo = TryParseLogEventInfo(nLogLogLevel, messageParameters) ?? CreateLogEventInfo(nLogLogLevel, formatter(state, exception), messageParameters); if (exception != null) { eventInfo.Exception = exception; } CaptureEventId(eventInfo, eventId); if (messageParameters == null) { CaptureMessageProperties(eventInfo, state); } _logger.Log(typeof(Microsoft.Extensions.Logging.ILogger), eventInfo); }
/// <summary> /// Allocates object[]-array for <see cref="LogEventInfo.Parameters"/> after checking /// for mismatch between Microsoft Extension Logging and NLog Message Template Parser /// </summary> /// <remarks> /// Cannot trust the parameters received from Microsoft Extension Logging, as extra parameters can be injected /// </remarks> private static object[] CreateLogEventInfoParameters(NLogMessageParameterList messageParameters, MessageTemplateParameters messagetTemplateParameters, out List <MessageTemplateParameter> extraProperties) { if (AllParameterCorrectlyPositionalMapped(messageParameters, messagetTemplateParameters)) { // Everything is mapped correctly, inject messageParameters directly as params-array extraProperties = null; var paramsArray = new object[messagetTemplateParameters.Count]; for (int i = 0; i < paramsArray.Length; ++i) { paramsArray[i] = messageParameters[i].Value; } return(paramsArray); } else { // Resolves mismatch between the input from Microsoft Extension Logging TState and NLog Message Template Parser if (messagetTemplateParameters.IsPositional) { return(CreatePositionalLogEventInfoParameters(messageParameters, messagetTemplateParameters, out extraProperties)); } else { return(CreateStructuredLogEventInfoParameters(messageParameters, messagetTemplateParameters, out extraProperties)); } } }
private static object[] CreateStructuredLogEventInfoParameters(NLogMessageParameterList messageParameters, MessageTemplateParameters messagetTemplateParameters, out List <MessageTemplateParameter> extraProperties) { extraProperties = null; var paramsArray = new object[messagetTemplateParameters.Count]; int startPos = 0; for (int i = 0; i < messageParameters.Count; ++i) { bool extraProperty = true; for (int j = startPos; j < messagetTemplateParameters.Count; ++j) { if (messageParameters[i].Name == messagetTemplateParameters[j].Name) { extraProperty = false; paramsArray[j] = messageParameters[i].Value; if (startPos == j) { startPos++; } break; } } if (extraProperty) { extraProperties = AddExtraProperty(extraProperties, messageParameters[i]); } } return(paramsArray); }
private static void SetEventInfoParameters(LogEventInfo eventInfo, NLogMessageParameterList messageTemplateParameters) { eventInfo.Parameters = new object[messageTemplateParameters.Count + 1]; for (int i = 0; i < messageTemplateParameters.Count; ++i) { eventInfo.Parameters[i] = messageTemplateParameters[i].Value; } }
private LogEventInfo CreateLogEventInfo(LogLevel nLogLogLevel, string message, IReadOnlyList <KeyValuePair <string, object> > parameterList) { if (parameterList != null && parameterList.Count > 1) { // More than a single parameter (last parameter is the {OriginalFormat}) var firstParameterName = parameterList[0].Key; if (!string.IsNullOrEmpty(firstParameterName)) { if (firstParameterName.Length != 1 || !char.IsDigit(firstParameterName[0])) { #if NETSTANDARD2_0 var originalFormat = parameterList[parameterList.Count - 1]; string originalMessage = null; if (originalFormat.Key == OriginalFormatPropertyName) { // Attempt to capture original message with placeholders originalMessage = originalFormat.Value as string; } var messageTemplateParameters = new NLogMessageParameterList(parameterList, originalMessage != null); var eventInfo = new LogEventInfo(nLogLogLevel, _logger.Name, originalMessage ?? message, messageTemplateParameters); if (originalMessage != null) { eventInfo.Parameters = new object[messageTemplateParameters.Count + 1]; for (int i = 0; i < messageTemplateParameters.Count; ++i) { eventInfo.Parameters[i] = messageTemplateParameters[i].Value; } eventInfo.Parameters[messageTemplateParameters.Count] = message; eventInfo.MessageFormatter = (l) => (string)l.Parameters[l.Parameters.Length - 1]; } return(eventInfo); #else var eventInfo = LogEventInfo.Create(nLogLogLevel, _logger.Name, message); for (int i = 0; i < parameterList.Count; ++i) { var parameter = parameterList[i]; if (string.IsNullOrEmpty(parameter.Key)) { break; // Skip capture of invalid parameters } var parameterName = parameter.Key; switch (parameterName[0]) { case '@': parameterName = parameterName.Substring(1); break; case '$': parameterName = parameterName.Substring(1); break; } eventInfo.Properties[parameterName] = parameter.Value; } return(eventInfo); #endif } } } return(LogEventInfo.Create(nLogLogLevel, _logger.Name, message)); }
private static void SetLogEventMessageFormatter(LogEventInfo logEvent, NLogMessageParameterList messageTemplateParameters, string formattedMessage) { var parameters = new object[messageTemplateParameters.Count + 1]; for (int i = 0; i < parameters.Length - 1; ++i) { parameters[i] = messageTemplateParameters[i].Value; } parameters[parameters.Length - 1] = formattedMessage; logEvent.Parameters = parameters; logEvent.MessageFormatter = (l) => (string)l.Parameters[l.Parameters.Length - 1]; }
/// <summary> /// Create Log Event with multiple parameters (last parameter is the {OriginalFormat}) /// </summary> private LogEventInfo CreateLogEventInfoWithMultipleParameters(LogLevel nLogLogLevel, string message, IReadOnlyList <KeyValuePair <string, object> > parameterList) { var messageTemplateParameters = new NLogMessageParameterList(parameterList); var originalMessage = messageTemplateParameters.OriginalMessage as string; var logEvent = new LogEventInfo(nLogLogLevel, _logger.Name, originalMessage ?? message, messageTemplateParameters); if (originalMessage != null) { SetLogEventMessageFormatter(logEvent, messageTemplateParameters, message); } return(logEvent); }
/// <summary> /// Are all parameters positional and correctly mapped? /// </summary> /// <param name="messageParameters"></param> /// <param name="messageTemplateParameters"></param> /// <returns>true if correct</returns> private static bool AllParameterCorrectlyPositionalMapped(NLogMessageParameterList messageParameters, MessageTemplateParameters messageTemplateParameters) { if (messageTemplateParameters.Count != messageParameters.Count) { return(false); } for (int i = 0; i < messageTemplateParameters.Count; ++i) { if (!messageParameters[i].Name.Equals(messageTemplateParameters[i].Name, StringComparison.Ordinal)) { return(false); } } return(true); }
/// <summary> /// Are all parameters positional and correctly mapped? /// </summary> /// <param name="messageParameters"></param> /// <param name="messagetTemplateParameters"></param> /// <returns>true if correct</returns> private static bool AllParameterCorrectlyPositionalMapped(NLogMessageParameterList messageParameters, MessageTemplateParameters messagetTemplateParameters) { if (messagetTemplateParameters.Count != messageParameters.Count || messagetTemplateParameters.IsPositional) { return(false); } for (int i = 0; i < messagetTemplateParameters.Count; ++i) { if (messagetTemplateParameters[i].Name != messageParameters[i].Name) { return(false); } } return(true); }
private LogEventInfo CreateLogEventInfo <TState>(LogLevel nLogLogLevel, EventId eventId, TState state, Exception exception, Func <TState, Exception, string> formatter) { if (_options.CaptureMessageProperties && state is IReadOnlyList <KeyValuePair <string, object> > messagePropertyList) { if (_options.CaptureMessageTemplates) { var messageParameters = NLogMessageParameterList.TryParse(messagePropertyList); if (messageParameters.Count == 0) { var logEvent = LogEventInfo.Create(nLogLogLevel, _logger.Name, formatter(state, exception)); CaptureEventIdProperties(logEvent, eventId); return(logEvent); } else { var logEvent = TryParseMessageTemplate(nLogLogLevel, messagePropertyList, messageParameters) ?? CaptureMessageTemplate(nLogLogLevel, formatter(state, exception), messagePropertyList, messageParameters); CaptureEventIdProperties(logEvent, eventId); return(logEvent); } } else { var logEvent = LogEventInfo.Create(nLogLogLevel, _logger.Name, formatter(state, exception)); CaptureMessagePropertiesList(logEvent, messagePropertyList); CaptureEventIdProperties(logEvent, eventId); return(logEvent); } } else { var logEvent = LogEventInfo.Create(nLogLogLevel, _logger.Name, formatter(state, exception)); if (_options.CaptureMessageProperties) { if (state is IEnumerable <KeyValuePair <string, object> > messageProperties) { CaptureMessageProperties(logEvent, messageProperties); } CaptureEventIdProperties(logEvent, eventId); } return(logEvent); } }
/// <summary> /// Create Log Event with multiple parameters (last parameter is the {OriginalFormat}) /// </summary> private LogEventInfo CreateLogEventInfoWithMultipleParameters(LogLevel nLogLogLevel, string message, IReadOnlyList <KeyValuePair <string, object> > parameterList) { var originalFormat = parameterList[parameterList.Count - 1]; string originalMessage = null; if (originalFormat.Key == OriginalFormatPropertyName) { // Attempt to capture original message with placeholders originalMessage = originalFormat.Value as string; } var messageTemplateParameters = new NLogMessageParameterList(parameterList, originalMessage != null); var eventInfo = new LogEventInfo(nLogLogLevel, _logger.Name, originalMessage ?? message, messageTemplateParameters); if (originalMessage != null) { SetEventInfoParameters(eventInfo, messageTemplateParameters); eventInfo.Parameters[messageTemplateParameters.Count] = message; eventInfo.MessageFormatter = (l) => (string)l.Parameters[l.Parameters.Length - 1]; } return(eventInfo); }
private LogEventInfo CreateLogEventInfo(LogLevel nLogLogLevel, string message, NLogMessageParameterList messageParameters) { if (messageParameters?.HasComplexParameters == false) { // Parsing not needed, we take the fast route var originalMessage = messageParameters.OriginalMessage as string; var eventInfo = new LogEventInfo(nLogLogLevel, _logger.Name, originalMessage ?? message, messageParameters.IsPositional ? _emptyParameterArray : messageParameters); if (originalMessage != null) { SetLogEventMessageFormatter(eventInfo, messageParameters, message); } return(eventInfo); } else { // Parsing failed or no messageParameters var eventInfo = LogEventInfo.Create(nLogLogLevel, _logger.Name, message); if (messageParameters?.Count > 0) { for (int i = 0; i < messageParameters.Count; ++i) { var property = messageParameters[i]; eventInfo.Properties[property.Name] = property.Value; } } return(eventInfo); } }
/// <summary> /// Convert IReadOnlyList to <see cref="NLogMessageParameterList"/> /// </summary> /// <param name="messageProperties"></param> /// <returns></returns> private NLogMessageParameterList TryParseMessageParameterList(IReadOnlyList <KeyValuePair <string, object> > messageProperties) { return((messageProperties != null && _options.CaptureMessageTemplates) ? NLogMessageParameterList.TryParse(messageProperties) : null); }
private LogEventInfo TryCaptureMessageTemplate(LogLevel nLogLogLevel, string message, IReadOnlyList <KeyValuePair <string, object> > messageProperties, NLogMessageParameterList messageParameters) { if (messageParameters?.HasComplexParameters == false) { // Parsing not needed, we take the fast route var originalMessage = messageParameters.GetOriginalMessage(messageProperties); var eventInfo = new LogEventInfo(nLogLogLevel, _logger.Name, originalMessage ?? message, messageParameters.IsPositional ? _emptyParameterArray : messageParameters); if (originalMessage != null) { SetLogEventMessageFormatter(eventInfo, messageParameters, message); } return(eventInfo); } return(null); }
private LogEventInfo CaptureMessageTemplate(LogLevel nLogLogLevel, string message, IReadOnlyList <KeyValuePair <string, object> > messageProperties, NLogMessageParameterList messageParameters) { // Parsing not needed, we take the fast route var originalMessage = messageParameters.GetOriginalMessage(messageProperties) ?? message; var logEvent = new LogEventInfo(nLogLogLevel, _logger.Name, originalMessage, messageParameters.IsPositional ? EmptyParameterArray : messageParameters); if (!ReferenceEquals(originalMessage, message)) { SetLogEventMessageFormatter(logEvent, messageParameters, message); } return(logEvent); }
/// <summary> /// Checks if the already parsed input message-parameters must be sent through /// the NLog MessageTemplate Parser for proper handling of message-template syntax (Ex. @) /// </summary> /// <remarks> /// Using the NLog MessageTemplate Parser will hurt performance: 1 x Microsoft Parser - 2 x NLog Parser - 1 x NLog Formatter /// </remarks> private LogEventInfo TryParseMessageTemplate(LogLevel nLogLogLevel, IReadOnlyList <KeyValuePair <string, object> > messageProperties, NLogMessageParameterList messageParameters) { if (messageParameters?.HasMessageTemplateSyntax(_options.ParseMessageTemplates) == true) { var originalMessage = messageParameters.GetOriginalMessage(messageProperties); var logEvent = new LogEventInfo(nLogLogLevel, _logger.Name, null, originalMessage, SingleItemArray); var messageTemplateParameters = logEvent.MessageTemplateParameters; // Forces parsing of OriginalMessage if (messageTemplateParameters.Count > 0) { // We have parsed the message and found parameters, now we need to do the parameter mapping CaptureLogEventInfoParameters(logEvent, messageParameters, messageTemplateParameters); return(logEvent); } return(null); // Parsing not possible } return(null); // Parsing not needed }
/// <summary> /// Checks if the already parsed input message-parameters must be sent through /// the NLog MessageTemplate Parser for proper handling of message-template syntax. /// </summary> /// <remarks> /// Using the NLog MesageTemplate Parser will hurt performance: 1 x Microsoft Parser - 2 x NLog Parser - 1 x NLog Formatter /// </remarks> private LogEventInfo TryParseMessageTemplate(LogLevel nLogLogLevel, IReadOnlyList <KeyValuePair <string, object> > messageProperties, out NLogMessageParameterList messageParameters) { messageParameters = TryParseMessageParameterList(messageProperties); if (messageParameters?.HasMessageTemplateSyntax(_options.ParseMessageTemplates) == true) { var originalMessage = messageParameters.GetOriginalMessage(messageProperties); var eventInfo = new LogEventInfo(nLogLogLevel, _logger.Name, null, originalMessage, _singleItemArray); var messagetTemplateParameters = eventInfo.MessageTemplateParameters; // Forces parsing of OriginalMessage if (messagetTemplateParameters.Count > 0) { // We have parsed the message and found parameters, now we need to do the parameter mapping eventInfo.Parameters = CreateLogEventInfoParameters(messageParameters, messagetTemplateParameters, out var extraProperties); AddExtraPropertiesToLogEvent(eventInfo, extraProperties); return(eventInfo); } return(null); // Parsing not possible } return(null); // Parsing not needed }
private LogEventInfo CreateLogEventInfo(LogLevel nLogLogLevel, string formattedMessage, IReadOnlyList <KeyValuePair <string, object> > messageProperties, NLogMessageParameterList messageParameters) { return(TryCaptureMessageTemplate(nLogLogLevel, formattedMessage, messageProperties, messageParameters) ?? CreateSimpleLogEventInfo(nLogLogLevel, formattedMessage, messageProperties, messageParameters)); }
private LogEventInfo CreateSimpleLogEventInfo(LogLevel nLogLogLevel, string message, IReadOnlyList <KeyValuePair <string, object> > messageProperties, NLogMessageParameterList messageParameters) { // Parsing failed or no messageParameters var eventInfo = LogEventInfo.Create(nLogLogLevel, _logger.Name, message); if (messageParameters != null) { for (int i = 0; i < messageParameters.Count; ++i) { var property = messageParameters[i]; eventInfo.Properties[property.Name] = property.Value; } } else if (messageProperties != null && _options.CaptureMessageProperties) { CaptureMessagePropertiesList(eventInfo, messageProperties); } return(eventInfo); }