in Libraries/src/Amazon.Lambda.RuntimeSupport/Helpers/Logging/AbstractLogMessageFormatter.cs [131:236]
public string ApplyMessageProperties(string messageTemplate, IReadOnlyList<MessageProperty> messageProperties, object[] messageArguments)
{
if(messageProperties.Count == 0 || messageArguments == null || messageArguments.Length == 0)
{
return messageTemplate;
}
// Check to see if the message template is using positions instead of names. For example
// "User bought {0} of {1}" is positional as opposed to "User bought {count} of {product"}.
var usePositional = UsingPositionalArguments(messageProperties);
var state = LogFormatParserState.InMessage;
// Builder used to create the message with the properties replaced. Set the initial capacity
// to the size of the message template plus 10% to give room for the values of message properties
// to be larger then the message property in the message themselves.
StringBuilder messageBuilder = new StringBuilder(capacity: (int)(messageTemplate.Length * 1.1));
// Builder used store potential message properties as we parse through the message. If the
// it turns out the potential message property is not a message property the contents of this
// builder are written back to the messageBuilder.
StringBuilder propertyBuilder = new StringBuilder();
int propertyIndex = 0;
for (int i = 0, l = messageTemplate.Length; i < l; i++)
{
var c = messageTemplate[i];
// If not using positional properties and we have hit the point there are more message properties then arguments
// then just add the rest of the message template onto the messageBuilder.
if (!usePositional && (messageProperties.Count <= propertyIndex || messageArguments.Length <= propertyIndex))
{
messageBuilder.Append(c);
continue;
}
switch (c)
{
case '{':
if (state == LogFormatParserState.InMessage)
{
// regardless of whether this is the opening of a parameter we'd still need to add {
propertyBuilder.Append(c);
state = LogFormatParserState.PossibleParameterOpen;
}
else if (state == LogFormatParserState.PossibleParameterOpen)
{
// We have hit an escaped "{" by the user using "{{". Since we now know we are
// not in a message properties write back the propertiesBuilder into
// messageBuilder and reset the propertyBuilder.
messageBuilder.Append(propertyBuilder.ToString());
propertyBuilder.Clear();
messageBuilder.Append(c);
state = LogFormatParserState.InMessage;
}
else
{
propertyBuilder.Append(c);
}
break;
case '}':
if (state == LogFormatParserState.InMessage)
{
messageBuilder.Append(c);
}
else
{
var property = messageProperties[propertyIndex];
object argument = null;
if(usePositional)
{
// If usePositional is true then we have confirmed the `Name` property is an int
var index = int.Parse(property.Name, CultureInfo.InvariantCulture);
if (index < messageArguments.Length)
{
argument = messageArguments[index];
}
}
else
{
argument = messageArguments[propertyIndex];
}
messageBuilder.Append(property.FormatForMessage(argument));
propertyIndex++;
propertyBuilder.Clear();
state = LogFormatParserState.InMessage;
}
break;
default:
if (state == LogFormatParserState.InMessage)
{
messageBuilder.Append(c);
}
else if (state == LogFormatParserState.PossibleParameterOpen)
{
// non-brace character after '{', transition to InParameter
propertyBuilder.Append(c);
state = LogFormatParserState.InParameter;
}
break;
}
}
return messageBuilder.ToString();
}