Skip to content

Commit b8f985d

Browse files
committed
README and refactor
1 parent 545342a commit b8f985d

13 files changed

+173
-18
lines changed

README.md

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# _Serilog.Expressions_
22

3-
A mini-language for filtering, enriching, and formatting Serilog
4-
events, ideal for embedding in JSON or XML configuration.
3+
An embeddable mini-language for filtering, enriching, and formatting Serilog
4+
events, ideal for use in JSON or XML configuration.
55

66
## Getting started
77

@@ -31,6 +31,13 @@ Log.Logger = new LoggerConfiguration()
3131
Events with a `RequestPath` property that matches the expression
3232
will be excluded by the filter.
3333

34+
> Note that if the expression syntax is invalid, an `ArgumentException` will
35+
be thrown from the `ByExcluding()` method, and by similar methods elsewhere
36+
in the package. To check expression syntax without throwing, see the
37+
`Try*()` methods in the `SerilogExpression` class.
38+
39+
#### An `appSettings.json` JSON configuration example
40+
3441
In [`appSettings.json`
3542
configuration](https://github.com/serilog/serilog-settings-configuration)
3643
this is written as:
@@ -51,10 +58,62 @@ this is written as:
5158
}
5259
```
5360

61+
#### An `<appSettings>` XML configuration example
62+
63+
In [XML configuration files](https://github.com/serilog/serilog-settings-appsettings),
64+
this is written as:
65+
66+
```xml
67+
<appSettings>
68+
<add key="serilog:using:Expressions" value="Serilog.Expressions" />
69+
<add key="serilog:filter:ByExcluding.expression" value="RequestPath like '/health%'" />
70+
</appSettings>
71+
```
72+
5473
### Enriching
5574

5675
### Formatting
5776

5877
## Language reference
5978

79+
## Working with the raw API
80+
81+
The package provides the class `SerilogExpression` in the `Serilog.Expressions` namespace
82+
for working with expressions.
6083

84+
```csharp
85+
if (SerilogExpression.TryCompile("RequestPath like '/health%'", out var compiled, out var error)
86+
{
87+
// `compiled` is a function that can be executed against `LogEvent`s:
88+
var result = compiled(someEvent);
89+
90+
// `result` will contain a `LogEventPropertyValue`, or `null` if the result of evaluating the
91+
// expression is undefined (for example if the event has no `RequestPath` property).
92+
if (result is ScalarValue value &&
93+
value.Value is bool matches &&
94+
matches)
95+
{
96+
Console.WriteLine("The event matched.");
97+
}
98+
}
99+
else
100+
{
101+
// `error` describes a syntax error.
102+
Console.WriteLine($"Couldn't compile the expression; {error}.");
103+
}
104+
```
105+
106+
Compiled expression delegates return `LogEventPropertyValue` because this is the most
107+
convenient type to work with in many Serilog scenarios (enrichers, sinks, ...). To
108+
convert the result to plain-old-.NET-types like `string`, `bool`, `Dictionary<K,V>` and
109+
`Array`, use the functions in the `Serilog.Expressions.ExpressionResult` class:
110+
111+
```csharp
112+
var result = compiled(someEvent);
113+
114+
// `true` only if `result` is a scalar Boolean `true`; `false` otherwise:
115+
if (ExpressionResult.IsTrue(result))
116+
{
117+
Console.WriteLine("The event matched.");
118+
}
119+
```

example/Sample/Program.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,11 @@ public static void Main()
1212
{
1313
SelfLog.Enable(Console.Error);
1414

15-
const string expr = "@l = 'Information' and AppId is not null and Items[?] like 'C%'";
16-
1715
using var log = new LoggerConfiguration()
1816
.Enrich.WithProperty("AppId", 10)
1917
.Enrich.WithComputed("FirstItem", "Items[0]")
2018
.Enrich.WithComputed("SourceContext", "coalesce(Substring(SourceContext, LastIndexOf(SourceContext, '.') + 1), SourceContext, '<no source>')")
21-
.Filter.ByIncludingOnly(expr)
19+
.Filter.ByIncludingOnly("@l = 'Information' and AppId is not null and Items[?] like 'C%'")
2220
.WriteTo.Console(outputTemplate:
2321
"[{Timestamp:HH:mm:ss} {Level:u3} ({SourceContext})] {Message:lj} (first item is {FirstItem}){NewLine}{Exception}")
2422
.WriteTo.Console(new OutputTemplate(

src/Serilog.Expressions/Expressions/CompiledExpression.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,18 @@
1-
using Serilog.Events;
1+
// Copyright Serilog Contributors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
using Serilog.Events;
216

317
#nullable enable
418

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright Serilog Contributors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
using Serilog.Events;
16+
using Serilog.Expressions.Runtime;
17+
18+
namespace Serilog.Expressions
19+
{
20+
/// <summary>
21+
/// Helper functions for working with the results of <see cref="CompiledExpression"/>s.
22+
/// </summary>
23+
public static class ExpressionResult
24+
{
25+
/// <summary>
26+
/// Test whether <paramref name="value"/> is <c langword="true">true</c>.
27+
/// </summary>
28+
/// <param name="value">The value to test, which may be <c langword="null">null</c>
29+
/// if the result of evaluating an expression was undefined.</param>
30+
/// <returns>Returns <c langword="true">true</c> if and only if the
31+
/// <paramref name="value"/> is a scalar Boolean with the
32+
/// value <c langword="true">true</c>. Returns <c langword="false">false</c>, otherwise.</returns>
33+
public static bool IsTrue(LogEventPropertyValue value)
34+
{
35+
return Coerce.IsTrue(value);
36+
}
37+
}
38+
}

src/Serilog.Expressions/Expressions/LoggingFilterSwitch.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ public bool IsEnabled(LogEvent logEvent)
8282
if (filter == null)
8383
return true;
8484

85-
return Coerce.True(filter.Item2(logEvent));
85+
return Coerce.IsTrue(filter.Item2(logEvent));
8686
}
8787

8888
/// <inheritdoc/>

src/Serilog.Expressions/Expressions/Runtime/Coerce.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public static bool Boolean(LogEventPropertyValue value, out bool boolean)
3838
return false;
3939
}
4040

41-
public static bool True(LogEventPropertyValue value)
41+
public static bool IsTrue(LogEventPropertyValue value)
4242
{
4343
return Boolean(value, out var b) && b;
4444
}

src/Serilog.Expressions/Expressions/Runtime/RuntimeOperators.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -322,12 +322,12 @@ public static LogEventPropertyValue _Internal_Any(LogEventPropertyValue items, L
322322

323323
if (items is SequenceValue arr)
324324
{
325-
return ScalarBoolean(arr.Elements.Any(e => Coerce.True(pred(e))));
325+
return ScalarBoolean(arr.Elements.Any(e => Coerce.IsTrue(pred(e))));
326326
}
327327

328328
if (items is StructureValue structure)
329329
{
330-
return ScalarBoolean(structure.Properties.Any(e => Coerce.True(pred(e.Value))));
330+
return ScalarBoolean(structure.Properties.Any(e => Coerce.IsTrue(pred(e.Value))));
331331
}
332332

333333
return null;
@@ -340,12 +340,12 @@ public static LogEventPropertyValue _Internal_All(LogEventPropertyValue items, L
340340

341341
if (items is SequenceValue arr)
342342
{
343-
return ScalarBoolean(arr.Elements.All(e => Coerce.True(pred(e))));
343+
return ScalarBoolean(arr.Elements.All(e => Coerce.IsTrue(pred(e))));
344344
}
345345

346346
if (items is StructureValue structure)
347347
{
348-
return ScalarBoolean(structure.Properties.All(e => Coerce.True(pred(e.Value))));
348+
return ScalarBoolean(structure.Properties.All(e => Coerce.IsTrue(pred(e.Value))));
349349
}
350350

351351
return null;

src/Serilog.Expressions/Expressions/SerilogExpression.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,18 @@
1-
using System;
1+
// Copyright Serilog Contributors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
using System;
216
using System.Linq;
317
using Serilog.Expressions.Compilation;
418
using Serilog.Expressions.Parsing;

src/Serilog.Expressions/LoggerEnrichmentConfigurationExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public static LoggerConfiguration When(
4343
if (configureEnricher == null) throw new ArgumentNullException(nameof(configureEnricher));
4444

4545
var compiled = SerilogExpression.Compile(expression);
46-
return loggerEnrichmentConfiguration.When(e => Coerce.True(compiled(e)), configureEnricher);
46+
return loggerEnrichmentConfiguration.When(e => Coerce.IsTrue(compiled(e)), configureEnricher);
4747
}
4848

4949
/// <summary>

src/Serilog.Expressions/LoggerFilterConfigurationExtensions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public static LoggerConfiguration ByIncludingOnly(this LoggerFilterConfiguration
2424
if (expression == null) throw new ArgumentNullException(nameof(expression));
2525

2626
var compiled = SerilogExpression.Compile(expression);
27-
return loggerFilterConfiguration.ByIncludingOnly(e => Coerce.True(compiled(e)));
27+
return loggerFilterConfiguration.ByIncludingOnly(e => Coerce.IsTrue(compiled(e)));
2828
}
2929

3030
/// <summary>
@@ -39,7 +39,7 @@ public static LoggerConfiguration ByExcluding(this LoggerFilterConfiguration log
3939
if (expression == null) throw new ArgumentNullException(nameof(expression));
4040

4141
var compiled = SerilogExpression.Compile(expression);
42-
return loggerFilterConfiguration.ByExcluding(e => Coerce.True(compiled(e)));
42+
return loggerFilterConfiguration.ByExcluding(e => Coerce.IsTrue(compiled(e)));
4343
}
4444

4545
/// <summary>

0 commit comments

Comments
 (0)