public ExpressionFilter(string filterExpression) { Func <LogEvent, bool> filter; // Our custom Serilog Functions to extend Serilog.Expressions // In this case we are plugging the gap for the missing Has() // function from porting away from Serilog.Filters.Expressions to Serilog.Expressions // Along with patching support for the more verbose built in property names var customSerilogFunctions = new SerilogLegacyNameResolver(typeof(SerilogExpressionsFunctions)); if (string.IsNullOrEmpty(filterExpression)) { return; } // If the expression is one word and doesn't contain a serilog operator then we can perform a like search if (!filterExpression.Contains(" ") && !filterExpression.ContainsAny(s_expressionOperators.Select(c => c))) { filter = PerformMessageLikeFilter(filterExpression); } else // check if it's a valid expression { // If the expression evaluates then make it into a filter if (SerilogExpression.TryCompile(filterExpression, null, customSerilogFunctions, out CompiledExpression compiled, out var error)) { filter = evt => { LogEventPropertyValue result = compiled(evt); return(ExpressionResult.IsTrue(result)); }; }
public void UserDefinedFunctionsAreCallableInExpressions() { var expr = SerilogExpression.Compile( "magic(10) + 3 = 55", new StaticMemberNameResolver(typeof(NameResolverTests))); Assert.True(Coerce.IsTrue(expr(Some.InformationEvent()))); }
public override string ToString() { if (_requiresEscape) { return($"@Properties['{SerilogExpression.EscapeStringContent(PropertyName)}']"); } return((IsBuiltIn ? "@" : "") + PropertyName); }
public override string ToString() { if (SerilogExpression.IsValidIdentifier(MemberName)) { return(Receiver + "." + MemberName); } return($"{Receiver}['{SerilogExpression.EscapeStringContent(MemberName)}']"); }
/// <summary> /// Exclude log events that match the provided expression. /// </summary> /// <param name="loggerFilterConfiguration">Filter configuration.</param> /// <param name="expression">The expression to apply.</param> /// <returns>The underlying <see cref="LoggerConfiguration"/>.</returns> public static LoggerConfiguration ByExcluding(this LoggerFilterConfiguration loggerFilterConfiguration, string expression) { if (loggerFilterConfiguration == null) { throw new ArgumentNullException(nameof(loggerFilterConfiguration)); } if (expression == null) { throw new ArgumentNullException(nameof(expression)); } var compiled = SerilogExpression.Compile(expression); return(loggerFilterConfiguration.ByExcluding(e => Coerce.IsTrue(compiled(e)))); }
private Func <LogEvent, bool>?PerformMessageLikeFilter(string filterExpression) { var filterSearch = $"@Message like '%{SerilogExpression.EscapeLikeExpressionContent(filterExpression)}%'"; if (SerilogExpression.TryCompile(filterSearch, out CompiledExpression? compiled, out var error)) { // `compiled` is a function that can be executed against `LogEvent`s: return(evt => { LogEventPropertyValue?result = compiled(evt); return ExpressionResult.IsTrue(result); }); } return(null); }
/// <summary> /// Enrich events with a property <paramref name="propertyName"/> computed by evaluating /// <paramref name="expression"/> in the context of the event. /// </summary> /// <param name="loggerEnrichmentConfiguration">Enrichment configuration.</param> /// <param name="propertyName">The name of the property to attach; if the property already /// exists, and <paramref name="expression"/> evaluates to a defined value, it will be overwritten.</param> /// <param name="expression">An expression to evaluate in the context of each event. If the result of /// evaluating the expression is defined, it will be attached to the event as <paramref name="propertyName"/>.</param> /// <returns>The underlying <see cref="LoggerConfiguration"/>.</returns> public static LoggerConfiguration WithComputed( this LoggerEnrichmentConfiguration loggerEnrichmentConfiguration, string propertyName, string expression) { if (propertyName == null) { throw new ArgumentNullException(nameof(propertyName)); } if (expression == null) { throw new ArgumentNullException(nameof(expression)); } var compiled = SerilogExpression.Compile(expression); return(loggerEnrichmentConfiguration.With(new ComputedPropertyEnricher(propertyName, compiled))); }
/// <summary> /// Write to a sink only when <paramref name="expression" /> evaluates to <c>true</c>. /// </summary> /// <param name="loggerSinkConfiguration">Sink configuration.</param> /// <param name="expression">An expression that evaluates to <c>true</c> when the /// supplied <see cref="T:Serilog.Events.LogEvent" /> /// should be written to the configured sink.</param> /// <param name="configureSink">An action that configures the wrapped sink.</param> /// <returns>Configuration object allowing method chaining.</returns> /// <returns>The underlying <see cref="LoggerConfiguration"/>.</returns> public static LoggerConfiguration Conditional( this LoggerSinkConfiguration loggerSinkConfiguration, string expression, Action <LoggerSinkConfiguration> configureSink) { if (loggerSinkConfiguration == null) { throw new ArgumentNullException(nameof(loggerSinkConfiguration)); } if (expression == null) { throw new ArgumentNullException(nameof(expression)); } if (configureSink == null) { throw new ArgumentNullException(nameof(configureSink)); } var compiled = SerilogExpression.Compile(expression); return(loggerSinkConfiguration.Conditional(e => Coerce.IsTrue(compiled(e)), configureSink)); }
/// <summary> /// Write to a sink only when <paramref name="expression" /> evaluates to <c>true</c>. /// </summary> /// <param name="loggerEnrichmentConfiguration">Enrichment configuration.</param> /// <param name="expression">An expression that evaluates to <c>true</c> when the supplied /// <see cref="T:Serilog.Events.LogEvent" /> should be enriched.</param> /// <param name="configureEnricher">An action that configures the wrapped enricher.</param> /// <returns>The underlying <see cref="LoggerConfiguration"/>.</returns> public static LoggerConfiguration When( this LoggerEnrichmentConfiguration loggerEnrichmentConfiguration, string expression, Action <LoggerEnrichmentConfiguration> configureEnricher) { if (loggerEnrichmentConfiguration == null) { throw new ArgumentNullException(nameof(loggerEnrichmentConfiguration)); } if (expression == null) { throw new ArgumentNullException(nameof(expression)); } if (configureEnricher == null) { throw new ArgumentNullException(nameof(configureEnricher)); } var compiled = SerilogExpression.Compile(expression); return(loggerEnrichmentConfiguration.When(e => Coerce.IsTrue(compiled(e)), configureEnricher)); }
public ComparisonBenchmark() { // Just the delegate invocation overhead _trivialFilter = evt => true; // `A == 3`, the old way _handwrittenFilter = evt => { if (evt.Properties.TryGetValue("A", out var a) && (a as ScalarValue)?.Value is int) { return((int)((ScalarValue)a).Value == 3); } return(false); }; // The code we're interested in; the `true.Equals()` overhead is normally added when // this is used with Serilog var compiled = SerilogExpression.Compile("A = 3"); _expressionFilter = evt => ExpressionResult.IsTrue(compiled(evt)); Assert.True(_trivialFilter(_event) && _handwrittenFilter(_event) && _expressionFilter(_event)); }
public LogResults Search(int pageNumber = 1, int pageSize = 100, string?filterExpression = null, SortOrder sort = SortOrder.Descending) { //If filter null - return a simple page of results if (filterExpression == null) { var totalRecords = _logItems.Count; var logMessages = _logItems .OrderBy(x => x.Timestamp, sort) .Skip(pageSize * (pageNumber - 1)) .Take(pageSize) .Select(x => new LogMessage { Timestamp = x.Timestamp, Level = x.Level, MessageTemplateText = x.MessageTemplate.Text, Exception = x.Exception?.ToString(), Properties = x.Properties, RenderedMessage = x.RenderMessage() }); return(new LogResults() { Logs = new PagedResult <LogMessage>(totalRecords, pageNumber, pageSize) { Items = logMessages }, MessageTemplates = GetMessageTemplates(_logItems) }); } Func <LogEvent, bool>?filter; // Our custom Serilog Functions in this case plugging the gap for missing Has() function var customSerilogFunctions = new LegacyNameResolver(typeof(SerilogExtensions)); // With an empty expression - ensure all logs are sent back if (filterExpression == string.Empty) { filter = evt => { // Return true/matches return(true); }; } // If the expression is one word and doesn't contain a serilog operator then we can perform a like search else if (!filterExpression.Contains(" ") && !filterExpression.ContainsAny(ExpressionOperators)) { filter = PerformMessageLikeFilter(filterExpression); } else { // Check if it's a valid expression // If the expression evaluates then make it into a filter if (SerilogExpression.TryCompile(filterExpression, null, customSerilogFunctions, out var compiled, out var error)) { // `compiled` is a function that can be executed against `LogEvent`s: filter = evt => { var result = compiled(evt); return(ExpressionResult.IsTrue(result)); }; }
public AmbientPropertyExpression(string propertyName, bool isBuiltIn) { PropertyName = propertyName ?? throw new ArgumentNullException(nameof(propertyName)); IsBuiltIn = isBuiltIn; _requiresEscape = !SerilogExpression.IsValidIdentifier(propertyName); }