/// <summary> /// Parses the specified condition string and turns it into /// <see cref="ConditionExpression"/> tree. /// </summary> /// <param name="expressionText">The expression to be parsed.</param> /// <param name="configurationItemFactories">Instance of <see cref="ConfigurationItemFactory"/> used to resolve references to condition methods and layout renderers.</param> /// <returns>The root of the expression syntax tree which can be used to get the value of the condition in a specified context.</returns> public static ConditionExpression ParseExpression(string expressionText, ConfigurationItemFactory configurationItemFactories) { if (expressionText == null) { return(null); } var parser = new ConditionParser(new SimpleStringReader(expressionText), configurationItemFactories); ConditionExpression expression = parser.ParseExpression(); if (!parser.tokenizer.IsEOF()) { throw new ConditionParseException("Unexpected token: " + parser.tokenizer.TokenValue); } return(expression); }
public void LayoutRendererThrows2() { string internalLogOutput = RunAndCaptureInternalLog( () => { ConfigurationItemFactory configurationItemFactory = new ConfigurationItemFactory(); configurationItemFactory.LayoutRenderers.RegisterDefinition("throwsException", typeof(ThrowsExceptionRenderer)); SimpleLayout l = new SimpleLayout("xx${throwsException:msg1}yy${throwsException:msg2}zz", configurationItemFactory); string output = l.Render(LogEventInfo.CreateNullEvent()); Assert.Equal("xxyyzz", output); }, LogLevel.Warn); Assert.True(internalLogOutput.IndexOf("msg1") >= 0, internalLogOutput); Assert.True(internalLogOutput.IndexOf("msg2") >= 0, internalLogOutput); }
private static void SetDefaultPropertyValue(ConfigurationItemFactory configurationItemFactory, LayoutRenderer layoutRenderer, string value, bool?throwConfigExceptions) { // what we've just read is not a parameterName, but a value // assign it to a default property (denoted by empty string) if (PropertyHelper.TryGetPropertyInfo(layoutRenderer, string.Empty, out var propertyInfo)) { PropertyHelper.SetPropertyFromString(layoutRenderer, propertyInfo.Name, value, configurationItemFactory); } else { var configException = new NLogConfigurationException($"{layoutRenderer.GetType()} has no default property to assign value {value}"); if (throwConfigExceptions ?? configException.MustBeRethrown()) { throw configException; } } }
private static LayoutRenderer ApplyWrappers(ConfigurationItemFactory configurationItemFactory, LayoutRenderer lr, List <LayoutRenderer> orderedWrappers) { for (int i = orderedWrappers.Count - 1; i >= 0; --i) { var newRenderer = (WrapperLayoutRendererBase)orderedWrappers[i]; InternalLogger.Trace("Wrapping {0} with {1}", lr.GetType(), newRenderer.GetType()); if (CanBeConvertedToLiteral(lr)) { lr = ConvertToLiteral(lr); } newRenderer.Inner = new SimpleLayout(new[] { lr }, string.Empty, configurationItemFactory); lr = newRenderer; } return(lr); }
private static void InitNLogConfigurationItemFactory() { // Default initialization code for ConfigurationItemFactory.Default spends // almost 0.5 sec in il-packed executable. (it scans whole types in assembly to find plugin types) // To avoid this slow-down, manual initialization is written. // If you need another layout-renderer, filter or anything else in NLog assembly, // please insert register code here. var factory = new ConfigurationItemFactory(new Assembly[0]); factory.LayoutRenderers.RegisterDefinition("time", typeof(TimeLayoutRenderer)); factory.LayoutRenderers.RegisterDefinition("longdate", typeof(LongDateLayoutRenderer)); factory.LayoutRenderers.RegisterDefinition("level", typeof(LevelLayoutRenderer)); factory.LayoutRenderers.RegisterDefinition("logger", typeof(LoggerNameLayoutRenderer)); factory.LayoutRenderers.RegisterDefinition("message", typeof(MessageLayoutRenderer)); factory.LayoutRenderers.RegisterDefinition("exception", typeof(ExceptionLayoutRenderer)); factory.LayoutRenderers.RegisterDefinition("uppercase", typeof(UppercaseLayoutRendererWrapper)); ConfigurationItemFactory.Default = factory; }
private static LayoutRenderer GetLayoutRenderer(ConfigurationItemFactory configurationItemFactory, string name, bool?throwConfigExceptions) { LayoutRenderer layoutRenderer; try { layoutRenderer = configurationItemFactory.LayoutRenderers.CreateInstance(name); } catch (Exception ex) { if (throwConfigExceptions ?? LogManager.ThrowConfigExceptions ?? LogManager.ThrowExceptions) { throw; // TODO NLog 5.0 throw NLogConfigurationException. Maybe also include entire input layout-string (if not too long) } InternalLogger.Error(ex, "Error parsing layout {0} will be ignored.", name); // replace with empty values layoutRenderer = new LiteralLayoutRenderer(string.Empty); } return(layoutRenderer); }
private static LayoutRenderer GetLayoutRenderer(ConfigurationItemFactory configurationItemFactory, string name, bool?throwConfigExceptions) { LayoutRenderer layoutRenderer; try { layoutRenderer = configurationItemFactory.LayoutRenderers.CreateInstance(name); } catch (Exception ex) { var configException = new NLogConfigurationException(ex, $"Error parsing layout {name}"); if (throwConfigExceptions ?? configException.MustBeRethrown()) { throw configException; } // replace with empty values layoutRenderer = new LiteralLayoutRenderer(string.Empty); } return(layoutRenderer); }
private static LayoutRenderer GetLayoutRenderer(ConfigurationItemFactory configurationItemFactory, string name) { LayoutRenderer layoutRenderer; try { layoutRenderer = configurationItemFactory.LayoutRenderers.CreateInstance(name); } catch (Exception ex) { if (LogManager.ThrowConfigExceptions ?? LogManager.ThrowExceptions) { throw; } InternalLogger.Error(ex, "Error parsing layout {0} will be ignored.", name); //replace with emptys layoutRenderer = new LiteralLayoutRenderer(string.Empty); } return(layoutRenderer); }
private static void SetDefaultPropertyValue(ConfigurationItemFactory configurationItemFactory, LayoutRenderer layoutRenderer, string parameterName) { // what we've just read is not a parameterName, but a value // assign it to a default property (denoted by empty string) PropertyInfo propertyInfo; if (PropertyHelper.TryGetPropertyInfo(layoutRenderer, string.Empty, out propertyInfo)) { if (typeof(SimpleLayout) == propertyInfo.PropertyType) { propertyInfo.SetValue(layoutRenderer, new SimpleLayout(parameterName), null); } else { string value = parameterName; PropertyHelper.SetPropertyFromString(layoutRenderer, propertyInfo.Name, value, configurationItemFactory); } } else { InternalLogger.Warn("{0} has no default property", layoutRenderer.GetType().FullName); } }
/// <summary> /// Parses the specified condition string and turns it into /// <see cref="ConditionExpression"/> tree. /// </summary> /// <param name="stringReader">The string reader.</param> /// <param name="configurationItemFactories">Instance of <see cref="ConfigurationItemFactory"/> used to resolve references to condition methods and layout renderers.</param> /// <returns> /// The root of the expression syntax tree which can be used to get the value of the condition in a specified context. /// </returns> internal static ConditionExpression ParseExpression(SimpleStringReader stringReader, ConfigurationItemFactory configurationItemFactories) { var parser = new ConditionParser(stringReader, configurationItemFactories); ConditionExpression expression = parser.ParseExpression(); return(expression); }
/// <summary> /// Initializes a new instance of the <see cref="ConditionParser" /> class. /// </summary> /// <param name="expressionText">The expression text.</param> /// <param name="configurationItemFactory">Instance of <see cref="ConfigurationItemFactory"/> used to resolve references to condition methods and layout renderers.</param> private ConditionParser(string expressionText, ConfigurationItemFactory configurationItemFactory) { this.configurationItemFactory = configurationItemFactory; this.tokenizer = new ConditionTokenizer(expressionText ?? string.Empty); }
private static LayoutRenderer ParseLayoutRenderer(ConfigurationItemFactory configurationItemFactory, SimpleStringReader stringReader, bool?throwConfigExceptions) { int ch = stringReader.Read(); Debug.Assert(ch == '{', "'{' expected in layout specification"); string name = ParseLayoutRendererName(stringReader); var layoutRenderer = GetLayoutRenderer(configurationItemFactory, name, throwConfigExceptions); Dictionary <Type, LayoutRenderer> wrappers = null; List <LayoutRenderer> orderedWrappers = null; ch = stringReader.Read(); while (ch != -1 && ch != '}') { string parameterName = ParseParameterName(stringReader).Trim(); if (stringReader.Peek() == '=') { stringReader.Read(); // skip the '=' PropertyInfo propertyInfo; LayoutRenderer parameterTarget = layoutRenderer; if (!PropertyHelper.TryGetPropertyInfo(layoutRenderer, parameterName, out propertyInfo)) { if (configurationItemFactory.AmbientProperties.TryGetDefinition(parameterName, out var wrapperType)) { wrappers = wrappers ?? new Dictionary <Type, LayoutRenderer>(); orderedWrappers = orderedWrappers ?? new List <LayoutRenderer>(); if (!wrappers.TryGetValue(wrapperType, out var wrapperRenderer)) { wrapperRenderer = configurationItemFactory.AmbientProperties.CreateInstance(parameterName); wrappers[wrapperType] = wrapperRenderer; orderedWrappers.Add(wrapperRenderer); } if (!PropertyHelper.TryGetPropertyInfo(wrapperRenderer, parameterName, out propertyInfo)) { propertyInfo = null; } else { parameterTarget = wrapperRenderer; } } } if (propertyInfo == null) { var value = ParseParameterValue(stringReader); if (!string.IsNullOrEmpty(parameterName) || !StringHelpers.IsNullOrWhiteSpace(value)) { // TODO NLog 5.0 Should throw exception when invalid configuration (Check throwConfigExceptions) InternalLogger.Warn("Skipping unrecognized property '{0}={1}` for ${{{2}}} ({3})", parameterName, value, name, layoutRenderer?.GetType()); } } else { if (typeof(Layout).IsAssignableFrom(propertyInfo.PropertyType)) { LayoutRenderer[] renderers = CompileLayout(configurationItemFactory, stringReader, throwConfigExceptions, true, out var txt); var nestedLayout = new SimpleLayout(renderers, txt, configurationItemFactory); propertyInfo.SetValue(parameterTarget, nestedLayout, null); } else if (typeof(ConditionExpression).IsAssignableFrom(propertyInfo.PropertyType)) { var conditionExpression = ConditionParser.ParseExpression(stringReader, configurationItemFactory); propertyInfo.SetValue(parameterTarget, conditionExpression, null); } else { string value = ParseParameterValue(stringReader); PropertyHelper.SetPropertyFromString(parameterTarget, parameterName, value, configurationItemFactory); } } } else { SetDefaultPropertyValue(configurationItemFactory, layoutRenderer, parameterName); } ch = stringReader.Read(); } if (orderedWrappers != null) { layoutRenderer = ApplyWrappers(configurationItemFactory, layoutRenderer, orderedWrappers); } return(layoutRenderer); }
private static bool TryNLogSpecificConversion(Type propertyType, string value, ConfigurationItemFactory configurationItemFactory, out object newValue) { if (DefaultPropertyConversionMapper.TryGetValue(propertyType, out var objectConverter)) { newValue = objectConverter.Invoke(value, configurationItemFactory); return(true); } newValue = null; return(false); }
private static LayoutRenderer ParseLayoutRenderer(ConfigurationItemFactory configurationItemFactory, SimpleStringReader stringReader, bool?throwConfigExceptions) { int ch = stringReader.Read(); Debug.Assert(ch == '{', "'{' expected in layout specification"); string name = ParseLayoutRendererName(stringReader); var layoutRenderer = GetLayoutRenderer(configurationItemFactory, name, throwConfigExceptions); var wrappers = new Dictionary <Type, LayoutRenderer>(); var orderedWrappers = new List <LayoutRenderer>(); ch = stringReader.Read(); while (ch != -1 && ch != '}') { string parameterName = ParseParameterName(stringReader).Trim(); if (stringReader.Peek() == '=') { stringReader.Read(); // skip the '=' PropertyInfo propertyInfo; LayoutRenderer parameterTarget = layoutRenderer; if (!PropertyHelper.TryGetPropertyInfo(layoutRenderer, parameterName, out propertyInfo)) { Type wrapperType; if (configurationItemFactory.AmbientProperties.TryGetDefinition(parameterName, out wrapperType)) { LayoutRenderer wrapperRenderer; if (!wrappers.TryGetValue(wrapperType, out wrapperRenderer)) { wrapperRenderer = configurationItemFactory.AmbientProperties.CreateInstance(parameterName); wrappers[wrapperType] = wrapperRenderer; orderedWrappers.Add(wrapperRenderer); } if (!PropertyHelper.TryGetPropertyInfo(wrapperRenderer, parameterName, out propertyInfo)) { propertyInfo = null; } else { parameterTarget = wrapperRenderer; } } } if (propertyInfo == null) { ParseParameterValue(stringReader); } else { if (typeof(Layout).IsAssignableFrom(propertyInfo.PropertyType)) { var nestedLayout = new SimpleLayout(); string txt; LayoutRenderer[] renderers = CompileLayout(configurationItemFactory, stringReader, throwConfigExceptions, true, out txt); nestedLayout.SetRenderers(renderers, txt); propertyInfo.SetValue(parameterTarget, nestedLayout, null); } else if (typeof(ConditionExpression).IsAssignableFrom(propertyInfo.PropertyType)) { var conditionExpression = ConditionParser.ParseExpression(stringReader, configurationItemFactory); propertyInfo.SetValue(parameterTarget, conditionExpression, null); } else { string value = ParseParameterValue(stringReader); PropertyHelper.SetPropertyFromString(parameterTarget, parameterName, value, configurationItemFactory); } } } else { SetDefaultPropertyValue(configurationItemFactory, layoutRenderer, parameterName); } ch = stringReader.Read(); } layoutRenderer = ApplyWrappers(configurationItemFactory, layoutRenderer, orderedWrappers); return(layoutRenderer); }
internal SimpleLayout(LayoutRenderer[] renderers, string text, ConfigurationItemFactory configurationItemFactory) { this.configurationItemFactory = configurationItemFactory; this.SetRenderers(renderers, text); }
/// <summary> /// Set value parsed from string. /// </summary> /// <param name="obj">object instance to set with property <paramref name="propertyName"/></param> /// <param name="propertyName">name of the property on <paramref name="obj"/></param> /// <param name="value">The value to be parsed.</param> /// <param name="configurationItemFactory"></param> internal static void SetPropertyFromString(object obj, string propertyName, string value, ConfigurationItemFactory configurationItemFactory) { var objType = obj.GetType(); InternalLogger.Debug("Setting '{0}.{1}' to '{2}'", objType, propertyName, value); if (!TryGetPropertyInfo(objType, propertyName, out var propInfo)) { throw new NotSupportedException($"Parameter {propertyName} not supported on {objType.Name}"); } try { Type propertyType = propInfo.PropertyType; if (!TryNLogSpecificConversion(propertyType, value, configurationItemFactory, out var newValue)) { if (propInfo.IsDefined(_arrayParameterAttribute.GetType(), false)) { throw new NotSupportedException($"Parameter {propertyName} of {objType.Name} is an array and cannot be assigned a scalar value."); } propertyType = Nullable.GetUnderlyingType(propertyType) ?? propertyType; if (!(TryGetEnumValue(propertyType, value, out newValue, true) || TryImplicitConversion(propertyType, value, out newValue) || TryFlatListConversion(obj, propInfo, value, configurationItemFactory, out newValue) || TryTypeConverterConversion(propertyType, value, out newValue))) { newValue = Convert.ChangeType(value, propertyType, CultureInfo.InvariantCulture); } } propInfo.SetValue(obj, newValue, null); } catch (TargetInvocationException ex) { throw new NLogConfigurationException($"Error when setting property '{propInfo.Name}' on {objType.Name}", ex.InnerException); } catch (Exception exception) { InternalLogger.Warn(exception, "Error when setting property '{0}' on '{1}'", propInfo.Name, objType); if (exception.MustBeRethrownImmediately()) { throw; } throw new NLogConfigurationException($"Error when setting property '{propInfo.Name}' on {objType.Name}", exception); } }
internal SimpleLayout(LayoutRenderer[] renderers, string text, ConfigurationItemFactory configurationItemFactory) { _configurationItemFactory = configurationItemFactory; OriginalText = text; SetRenderers(renderers, text); }
/// <summary> /// Try parse of string to (Generic) list, comma separated. /// </summary> /// <remarks> /// If there is a comma in the value, then (single) quote the value. For single quotes, use the backslash as escape /// </remarks> private static bool TryFlatListConversion(object obj, PropertyInfo propInfo, string valueRaw, ConfigurationItemFactory configurationItemFactory, out object newValue) { if (propInfo.PropertyType.IsGenericType() && TryCreateCollectionObject(obj, propInfo, valueRaw, out var newList, out var collectionAddMethod, out var propertyType)) { var values = valueRaw.SplitQuoted(',', '\'', '\\'); foreach (var value in values) { if (!(TryGetEnumValue(propertyType, value, out newValue, false) || TryNLogSpecificConversion(propertyType, value, configurationItemFactory, out newValue) || TryImplicitConversion(propertyType, value, out newValue) || TryTypeConverterConversion(propertyType, value, out newValue))) { newValue = Convert.ChangeType(value, propertyType, CultureInfo.InvariantCulture); } collectionAddMethod.Invoke(newList, new object[] { newValue }); } newValue = newList; return(true); } newValue = null; return(false); }
private static object TryParseConditionValue(string stringValue, ConfigurationItemFactory configurationItemFactory) { return(ConditionParser.ParseExpression(stringValue, configurationItemFactory)); }
private static object TryParseLayoutValue(string stringValue, ConfigurationItemFactory configurationItemFactory) { return(new SimpleLayout(stringValue, configurationItemFactory)); }
/// <summary> /// Initializes a new instance of the <see cref="ConditionParser"/> class. /// </summary> /// <param name="stringReader">The string reader.</param> /// <param name="configurationItemFactory">Instance of <see cref="ConfigurationItemFactory"/> used to resolve references to condition methods and layout renderers.</param> private ConditionParser(SimpleStringReader stringReader, ConfigurationItemFactory configurationItemFactory) { _configurationItemFactory = configurationItemFactory; _tokenizer = new ConditionTokenizer(stringReader); }
public void SetUp() { _config = new ConfigurationItemFactory(GetType().Assembly, typeof(Logger).Assembly); }
/// <summary> /// Initializes a new instance of the <see cref="SimpleLayout"/> class. /// </summary> /// <param name="txt">The layout string to parse.</param> /// <param name="configurationItemFactory">The NLog factories to use when creating references to layout renderers.</param> public SimpleLayout(string txt, ConfigurationItemFactory configurationItemFactory) { this.configurationItemFactory = configurationItemFactory; this.Text = txt; }
private static bool TryNLogSpecificConversion(Type propertyType, string value, out object newValue, ConfigurationItemFactory configurationItemFactory) { if (propertyType == typeof(Layout) || propertyType == typeof(SimpleLayout)) { newValue = new SimpleLayout(value, configurationItemFactory); return(true); } if (propertyType == typeof(ConditionExpression)) { newValue = ConditionParser.ParseExpression(value, configurationItemFactory); return(true); } newValue = null; return(false); }
public void ConfigurationItemFactoryDefaultTest() { var cif = new ConfigurationItemFactory(); Assert.IsType(typeof(DebugTarget), cif.CreateInstance(typeof(DebugTarget))); }
internal static void SetPropertyFromString(object o, string name, string value, ConfigurationItemFactory configurationItemFactory) { InternalLogger.Debug("Setting '{0}.{1}' to '{2}'", o.GetType().Name, name, value); PropertyInfo propInfo; if (!TryGetPropertyInfo(o, name, out propInfo)) { throw new NotSupportedException("Parameter " + name + " not supported on " + o.GetType().Name); } try { if (propInfo.IsDefined(typeof(ArrayParameterAttribute), false)) { throw new NotSupportedException("Parameter " + name + " of " + o.GetType().Name + " is an array and cannot be assigned a scalar value."); } object newValue; Type propertyType = propInfo.PropertyType; propertyType = Nullable.GetUnderlyingType(propertyType) ?? propertyType; if (!TryNLogSpecificConversion(propertyType, value, out newValue, configurationItemFactory)) { if (!TryGetEnumValue(propertyType, value, out newValue)) { if (!TryImplicitConversion(propertyType, value, out newValue)) { if (!TrySpecialConversion(propertyType, value, out newValue)) { newValue = Convert.ChangeType(value, propertyType, CultureInfo.InvariantCulture); } } } } propInfo.SetValue(o, newValue, null); } catch (TargetInvocationException ex) { throw new NLogConfigurationException("Error when setting property '" + propInfo.Name + "' on " + o, ex.InnerException); } catch (Exception exception) { if (exception.MustBeRethrown()) { throw; } throw new NLogConfigurationException("Error when setting property '" + propInfo.Name + "' on " + o, exception); } }
/// <summary> /// Initializes a new instance of the <see cref="SimpleLayout"/> class. /// </summary> /// <param name="txt">The layout string to parse.</param> /// <param name="configurationItemFactory">The NLog factories to use when creating references to layout renderers.</param> public SimpleLayout(string txt, ConfigurationItemFactory configurationItemFactory) : this(txt, configurationItemFactory, null) { }
private static LayoutRenderer ParseLayoutRenderer(ConfigurationItemFactory configurationItemFactory, Tokenizer sr) { int ch = sr.Read(); Debug.Assert(ch == '{', "'{' expected in layout specification"); string name = ParseLayoutRendererName(sr); LayoutRenderer lr = configurationItemFactory.LayoutRenderers.CreateInstance(name); var wrappers = new Dictionary <Type, LayoutRenderer>(); var orderedWrappers = new List <LayoutRenderer>(); ch = sr.Read(); while (ch != -1 && ch != '}') { string parameterName = ParseParameterName(sr).Trim(); if (sr.Peek() == '=') { sr.Read(); // skip the '=' PropertyInfo pi; LayoutRenderer parameterTarget = lr; if (!PropertyHelper.TryGetPropertyInfo(lr, parameterName, out pi)) { Type wrapperType; if (configurationItemFactory.AmbientProperties.TryGetDefinition(parameterName, out wrapperType)) { LayoutRenderer wrapperRenderer; if (!wrappers.TryGetValue(wrapperType, out wrapperRenderer)) { wrapperRenderer = configurationItemFactory.AmbientProperties.CreateInstance(parameterName); wrappers[wrapperType] = wrapperRenderer; orderedWrappers.Add(wrapperRenderer); } if (!PropertyHelper.TryGetPropertyInfo(wrapperRenderer, parameterName, out pi)) { pi = null; } else { parameterTarget = wrapperRenderer; } } } if (pi == null) { ParseParameterValue(sr); } else { if (typeof(Layout).IsAssignableFrom(pi.PropertyType)) { var nestedLayout = new SimpleLayout(); string txt; LayoutRenderer[] renderers = CompileLayout(configurationItemFactory, sr, true, out txt); nestedLayout.SetRenderers(renderers, txt); pi.SetValue(parameterTarget, nestedLayout, null); } else { string value = ParseParameterValue(sr); PropertyHelper.SetPropertyFromString(parameterTarget, parameterName, value); } } } else { // what we've just read is not a parameterName, but a value // assign it to a default property (denoted by empty string) PropertyInfo pi; if (PropertyHelper.TryGetPropertyInfo(lr, string.Empty, out pi)) { if (typeof(SimpleLayout) == pi.PropertyType) { pi.SetValue(lr, new SimpleLayout(parameterName), null); } else { string value = parameterName; PropertyHelper.SetPropertyFromString(lr, pi.Name, value); } } else { InternalLogger.Warn("{0} has no default property", lr.GetType().FullName); } } ch = sr.Read(); } lr = ApplyWrappers(configurationItemFactory, lr, orderedWrappers); return(lr); }
internal static LayoutRenderer[] CompileLayout(ConfigurationItemFactory configurationItemFactory, SimpleStringReader sr, bool?throwConfigExceptions, bool isNested, out string text) { var result = new List <LayoutRenderer>(); var literalBuf = new StringBuilder(); int ch; int p0 = sr.Position; while ((ch = sr.Peek()) != -1) { if (isNested) { //possible escape char `\` if (ch == '\\') { sr.Read(); var nextChar = sr.Peek(); //escape chars if (EndOfLayout(nextChar)) { //read next char and append sr.Read(); literalBuf.Append((char)nextChar); } else { //don't treat \ as escape char and just read it literalBuf.Append('\\'); } continue; } if (EndOfLayout(ch)) { //end of innerlayout. // `}` is when double nested inner layout. // `:` when single nested layout break; } } sr.Read(); //detect `${` (new layout-renderer) if (ch == '$' && sr.Peek() == '{') { //stash already found layout-renderer. AddLiteral(literalBuf, result); LayoutRenderer newLayoutRenderer = ParseLayoutRenderer(configurationItemFactory, sr, throwConfigExceptions); if (CanBeConvertedToLiteral(newLayoutRenderer)) { newLayoutRenderer = ConvertToLiteral(newLayoutRenderer); } // layout renderer result.Add(newLayoutRenderer); } else { literalBuf.Append((char)ch); } } AddLiteral(literalBuf, result); int p1 = sr.Position; MergeLiterals(result); text = sr.Substring(p0, p1); return(result.ToArray()); }
/// <summary> /// Initializes a new instance of the <see cref="SimpleLayout"/> class. /// </summary> /// <param name="txt">The layout string to parse.</param> /// <param name="configurationItemFactory">The NLog factories to use when creating references to layout renderers.</param> /// <param name="throwConfigExceptions">Whether <see cref="NLogConfigurationException"/> should be thrown on parse errors.</param> internal SimpleLayout(string txt, ConfigurationItemFactory configurationItemFactory, bool?throwConfigExceptions) { _configurationItemFactory = configurationItemFactory; SetLayoutText(txt, throwConfigExceptions); }