private static object[] CreateStructuredLogEventInfoParameters(NLogMessageParameterList messageParameters, MessageTemplateParameters messagetTemplateParameters, out List <MessageTemplateParameter> extraProperties)
        {
            extraProperties = null;

            var paramsArray = new object[messagetTemplateParameters.Count];
            var startPos    = 0;

            for (var i = 0; i < messageParameters.Count; ++i)
            {
                var extraProperty = true;
                for (var 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 object[] CreatePositionalLogEventInfoParameters(NLogMessageParameterList messageParameters, MessageTemplateParameters messagetTemplateParameters, out List <MessageTemplateParameter> extraProperties)
        {
            extraProperties = null;

            var maxIndex = FindMaxIndex(messagetTemplateParameters);

            object[] paramsArray = null;
            for (var i = 0; i < messageParameters.Count; ++i)
            {
                // First positional name is the startPos
                if (char.IsDigit(messageParameters[i].Name[0]) && paramsArray == null)
                {
                    paramsArray = new object[maxIndex + 1];
                    for (var j = 0; j <= maxIndex; ++j)
                    {
                        if (i + j < messageParameters.Count)
                        {
                            paramsArray[j] = messageParameters[i + j].Value;
                        }
                    }
                    i += maxIndex;
                }
                else
                {
                    extraProperties = AddExtraProperty(extraProperties, messageParameters[i]);
                }
            }

            return(paramsArray ?? new object[maxIndex + 1]);
        }
 /// <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 (var 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 void SetLogEventMessageFormatter(LogEventInfo logEvent, NLogMessageParameterList messageTemplateParameters, string formattedMessage)
        {
            var parameters = new object[messageTemplateParameters.Count + 1];

            for (var 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>
        /// 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 (var i = 0; i < messagetTemplateParameters.Count; ++i)
            {
                if (messagetTemplateParameters[i].Name != messageParameters[i].Name)
                {
                    return(false);
                }
            }

            return(true);
        }
        /// <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, IList <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, IList <KeyValuePair <string, object> > messageProperties, NLogMessageParameterList messageParameters)
 {
     return(TryCaptureMessageTemplate(nLogLogLevel, formattedMessage, messageProperties, messageParameters) ??
            CreateSimpleLogEventInfo(nLogLogLevel, formattedMessage, messageProperties, messageParameters));
 }
        private LogEventInfo CreateSimpleLogEventInfo(LogLevel nLogLogLevel, string message, IList <KeyValuePair <string, object> > messageProperties, NLogMessageParameterList messageParameters)
        {
            // Parsing failed or no messageParameters
            var eventInfo = LogEventInfo.Create(nLogLogLevel, _logger.Name, message);

            if (messageParameters != null)
            {
                for (var 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);
        }
 private LogEventInfo TryCaptureMessageTemplate(LogLevel nLogLogLevel, string message, IList <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);
 }
 /// <summary>
 /// Convert IList to <see cref="NLogMessageParameterList"/>
 /// </summary>
 /// <param name="messageProperties"></param>
 /// <returns></returns>
 private NLogMessageParameterList TryParseMessageParameterList(IList <KeyValuePair <string, object> > messageProperties)
 {
     return((messageProperties != null && _options.CaptureMessageTemplates)
         ? NLogMessageParameterList.TryParse(messageProperties)
         : null);
 }