Skip to content

Commit 63fe8de

Browse files
authored
Merge pull request #44 from serilog/dev
3.1.0 Release
2 parents c6192d6 + 44e69de commit 63fe8de

19 files changed

+486
-65
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ calling a function will be undefined if:
195195
| `LastIndexOf(s, t)` | Returns the last index of substring `t` in string `s`, or -1 if the substring does not appear. |
196196
| `Length(x)` | Returns the length of a string or array. |
197197
| `Now()` | Returns `DateTimeOffset.Now`. |
198+
| `Rest()` | In an `ExpressionTemplate`, returns an object containing the first-class event properties not otherwise referenced in the template or the event's message. |
198199
| `Round(n, m)` | Round the number `n` to `m` decimal places. |
199200
| `StartsWith(s, t)` | Tests whether the string `s` starts with substring `t`. |
200201
| `Substring(s, start, [length])` | Return the substring of string `s` from `start` to the end of the string, or of `length` characters, if this argument is supplied. |

example/Sample/Program.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,11 @@ public static void Main()
2323
static void TextFormattingExample1()
2424
{
2525
using var log = new LoggerConfiguration()
26+
.Enrich.WithProperty("Application", "Sample")
2627
.WriteTo.Console(new ExpressionTemplate(
2728
"[{@t:HH:mm:ss} {@l:u3}" +
2829
"{#if SourceContext is not null} ({Substring(SourceContext, LastIndexOf(SourceContext, '.') + 1)}){#end}] " +
29-
"{@m} (first item is {coalesce(Items[0], '<empty>')})\n{@x}",
30+
"{@m} (first item is {coalesce(Items[0], '<empty>')}) {rest()}\n{@x}",
3031
theme: TemplateTheme.Code))
3132
.CreateLogger();
3233

src/Serilog.Expressions/Expressions/Compilation/Linq/LinqExpressionCompiler.cs

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ class LinqExpressionCompiler : SerilogExpressionTransformer<ExpressionBody>
7171
static readonly MethodInfo TryGetStructurePropertyValueMethod = typeof(Intrinsics)
7272
.GetMethod(nameof(Intrinsics.TryGetStructurePropertyValue), BindingFlags.Static | BindingFlags.Public)!;
7373

74+
static readonly PropertyInfo EvaluationContextLogEventProperty = typeof(EvaluationContext)
75+
.GetProperty(nameof(EvaluationContext.LogEvent), BindingFlags.Instance | BindingFlags.Public)!;
76+
7477
ParameterExpression Context { get; } = LX.Variable(typeof(EvaluationContext), "ctx");
7578

7679
LinqExpressionCompiler(IFormatProvider? formatProvider, NameResolver nameResolver)
@@ -93,36 +96,44 @@ ExpressionBody Splice(Expression<Evaluatable> lambda)
9396
return ParameterReplacementVisitor.ReplaceParameters(lambda, Context);
9497
}
9598

96-
protected override ExpressionBody Transform(CallExpression lx)
99+
protected override ExpressionBody Transform(CallExpression call)
97100
{
98-
if (!_nameResolver.TryResolveFunctionName(lx.OperatorName, out var m))
99-
throw new ArgumentException($"The function name `{lx.OperatorName}` was not recognized.");
101+
if (!_nameResolver.TryResolveFunctionName(call.OperatorName, out var m))
102+
throw new ArgumentException($"The function name `{call.OperatorName}` was not recognized.");
100103

101104
var methodParameters = m.GetParameters();
102105

103106
var parameterCount = methodParameters.Count(pi => pi.ParameterType == typeof(LogEventPropertyValue));
104-
if (parameterCount != lx.Operands.Length)
105-
throw new ArgumentException($"The function `{lx.OperatorName}` requires {parameterCount} arguments.");
107+
if (parameterCount != call.Operands.Length)
108+
throw new ArgumentException($"The function `{call.OperatorName}` requires {parameterCount} arguments.");
106109

107-
var operands = lx.Operands.Select(Transform).ToList();
110+
var operands = new Queue<LX>(call.Operands.Select(Transform));
108111

109112
// `and` and `or` short-circuit to save execution time; unlike the earlier Serilog.Filters.Expressions, nothing else does.
110-
if (Operators.SameOperator(lx.OperatorName, Operators.RuntimeOpAnd))
111-
return CompileLogical(LX.AndAlso, operands[0], operands[1]);
113+
if (Operators.SameOperator(call.OperatorName, Operators.RuntimeOpAnd))
114+
return CompileLogical(LX.AndAlso, operands.Dequeue(), operands.Dequeue());
112115

113-
if (Operators.SameOperator(lx.OperatorName, Operators.RuntimeOpOr))
114-
return CompileLogical(LX.OrElse, operands[0], operands[1]);
116+
if (Operators.SameOperator(call.OperatorName, Operators.RuntimeOpOr))
117+
return CompileLogical(LX.OrElse, operands.Dequeue(), operands.Dequeue());
115118

116-
for (var i = 0; i < methodParameters.Length; ++i)
119+
var boundParameters = new List<LX>(methodParameters.Length);
120+
foreach (var pi in methodParameters)
117121
{
118-
var pi = methodParameters[i];
119-
if (pi.ParameterType == typeof(StringComparison))
120-
operands.Insert(i, LX.Constant(lx.IgnoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal));
122+
if (pi.ParameterType == typeof(LogEventPropertyValue))
123+
boundParameters.Add(operands.Dequeue());
124+
else if (pi.ParameterType == typeof(StringComparison))
125+
boundParameters.Add(LX.Constant(call.IgnoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal));
121126
else if (pi.ParameterType == typeof(IFormatProvider))
122-
operands.Insert(i, LX.Constant(_formatProvider, typeof(IFormatProvider)));
127+
boundParameters.Add(LX.Constant(_formatProvider, typeof(IFormatProvider)));
128+
else if (pi.ParameterType == typeof(LogEvent))
129+
boundParameters.Add(LX.Property(Context, EvaluationContextLogEventProperty));
130+
else if (_nameResolver.TryBindFunctionParameter(pi, out var binding))
131+
boundParameters.Add(LX.Constant(binding, pi.ParameterType));
132+
else
133+
throw new ArgumentException($"The method `{m.Name}` implementing function `{call.OperatorName}` has parameter `{pi.Name}` which could not be bound.");
123134
}
124135

125-
return LX.Call(m, operands);
136+
return LX.Call(m, boundParameters);
126137
}
127138

128139
static ExpressionBody CompileLogical(Func<ExpressionBody, ExpressionBody, ExpressionBody> apply, ExpressionBody lhs, ExpressionBody rhs)
@@ -138,8 +149,8 @@ static ExpressionBody CompileLogical(Func<ExpressionBody, ExpressionBody, Expres
138149

139150
protected override ExpressionBody Transform(AccessorExpression spx)
140151
{
141-
var recv = Transform(spx.Receiver);
142-
return LX.Call(TryGetStructurePropertyValueMethod, LX.Constant(StringComparison.OrdinalIgnoreCase), recv, LX.Constant(spx.MemberName, typeof(string)));
152+
var receiver = Transform(spx.Receiver);
153+
return LX.Call(TryGetStructurePropertyValueMethod, LX.Constant(StringComparison.OrdinalIgnoreCase), receiver, LX.Constant(spx.MemberName, typeof(string)));
143154
}
144155

145156
protected override ExpressionBody Transform(ConstantExpression cx)

src/Serilog.Expressions/Expressions/Compilation/OrderedNameResolver.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,5 +39,17 @@ public override bool TryResolveFunctionName(string name, [MaybeNullWhen(false)]
3939
implementation = null;
4040
return false;
4141
}
42+
43+
public override bool TryBindFunctionParameter(ParameterInfo parameter, [MaybeNullWhen(false)] out object boundValue)
44+
{
45+
foreach (var resolver in _orderedResolvers)
46+
{
47+
if (resolver.TryBindFunctionParameter(parameter, out boundValue))
48+
return true;
49+
}
50+
51+
boundValue = null;
52+
return false;
53+
}
4254
}
4355
}

src/Serilog.Expressions/Expressions/Compilation/Text/LikeSyntaxTransformer.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,21 +30,21 @@ public static Expression Rewrite(Expression expression)
3030
return Instance.Transform(expression);
3131
}
3232

33-
protected override Expression Transform(CallExpression lx)
33+
protected override Expression Transform(CallExpression call)
3434
{
35-
if (lx.Operands.Length != 2)
36-
return base.Transform(lx);
35+
if (call.Operands.Length != 2)
36+
return base.Transform(call);
3737

38-
if (Operators.SameOperator(lx.OperatorName, Operators.IntermediateOpLike))
39-
return TryCompileLikeExpression(lx.IgnoreCase, lx.Operands[0], lx.Operands[1]);
38+
if (Operators.SameOperator(call.OperatorName, Operators.IntermediateOpLike))
39+
return TryCompileLikeExpression(call.IgnoreCase, call.Operands[0], call.Operands[1]);
4040

41-
if (Operators.SameOperator(lx.OperatorName, Operators.IntermediateOpNotLike))
41+
if (Operators.SameOperator(call.OperatorName, Operators.IntermediateOpNotLike))
4242
return new CallExpression(
4343
false,
4444
Operators.RuntimeOpStrictNot,
45-
TryCompileLikeExpression(lx.IgnoreCase, lx.Operands[0], lx.Operands[1]));
45+
TryCompileLikeExpression(call.IgnoreCase, call.Operands[0], call.Operands[1]));
4646

47-
return base.Transform(lx);
47+
return base.Transform(call);
4848
}
4949

5050
Expression TryCompileLikeExpression(bool ignoreCase, Expression corpus, Expression like)

src/Serilog.Expressions/Expressions/Compilation/Text/TextMatchingTransformer.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,22 +30,22 @@ public static Expression Rewrite(Expression expression)
3030
return Instance.Transform(expression);
3131
}
3232

33-
protected override Expression Transform(CallExpression lx)
33+
protected override Expression Transform(CallExpression call)
3434
{
35-
if (lx.Operands.Length != 2)
36-
return base.Transform(lx);
35+
if (call.Operands.Length != 2)
36+
return base.Transform(call);
3737

38-
if (Operators.SameOperator(lx.OperatorName, Operators.OpIndexOfMatch))
39-
return TryCompileIndexOfMatch(lx.IgnoreCase, lx.Operands[0], lx.Operands[1]);
38+
if (Operators.SameOperator(call.OperatorName, Operators.OpIndexOfMatch))
39+
return TryCompileIndexOfMatch(call.IgnoreCase, call.Operands[0], call.Operands[1]);
4040

41-
if (Operators.SameOperator(lx.OperatorName, Operators.OpIsMatch))
41+
if (Operators.SameOperator(call.OperatorName, Operators.OpIsMatch))
4242
return new CallExpression(
4343
false,
4444
Operators.RuntimeOpNotEqual,
45-
TryCompileIndexOfMatch(lx.IgnoreCase, lx.Operands[0], lx.Operands[1]),
45+
TryCompileIndexOfMatch(call.IgnoreCase, call.Operands[0], call.Operands[1]),
4646
new ConstantExpression(new ScalarValue(-1)));
4747

48-
return base.Transform(lx);
48+
return base.Transform(call);
4949
}
5050

5151
Expression TryCompileIndexOfMatch(bool ignoreCase, Expression corpus, Expression regex)

src/Serilog.Expressions/Expressions/Compilation/Transformations/IdentityTransformer.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,21 @@ bool TryTransform(Expression expr, out Expression result)
2525
return !ReferenceEquals(expr, result);
2626
}
2727

28-
protected override Expression Transform(CallExpression lx)
28+
protected override Expression Transform(CallExpression call)
2929
{
3030
var any = false;
3131
var operands = new List<Expression>();
32-
foreach (var op in lx.Operands)
32+
foreach (var op in call.Operands)
3333
{
3434
if (TryTransform(op, out var result))
3535
any = true;
3636
operands.Add(result);
3737
}
3838

3939
if (!any)
40-
return lx;
40+
return call;
4141

42-
return new CallExpression(lx.IgnoreCase, lx.OperatorName, operands.ToArray());
42+
return new CallExpression(call.IgnoreCase, call.OperatorName, operands.ToArray());
4343
}
4444

4545
protected override Expression Transform(ConstantExpression cx)

src/Serilog.Expressions/Expressions/Compilation/Transformations/FilterExpressionTransformer`1.cs renamed to src/Serilog.Expressions/Expressions/Compilation/Transformations/SerilogExpressionTransformer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ protected virtual TResult Transform(Expression expression)
4141
};
4242
}
4343

44-
protected abstract TResult Transform(CallExpression lx);
44+
protected abstract TResult Transform(CallExpression call);
4545
protected abstract TResult Transform(ConstantExpression cx);
4646
protected abstract TResult Transform(AmbientNameExpression px);
4747
protected abstract TResult Transform(LocalNameExpression nlx);

src/Serilog.Expressions/Expressions/Compilation/Variadics/VariadicCallRewriter.cs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,38 +28,38 @@ public static Expression Rewrite(Expression expression)
2828
return Instance.Transform(expression);
2929
}
3030

31-
protected override Expression Transform(CallExpression lx)
31+
protected override Expression Transform(CallExpression call)
3232
{
33-
if (Operators.SameOperator(lx.OperatorName, Operators.OpSubstring) && lx.Operands.Length == 2)
33+
if (Operators.SameOperator(call.OperatorName, Operators.OpSubstring) && call.Operands.Length == 2)
3434
{
35-
var operands = lx.Operands
35+
var operands = call.Operands
3636
.Select(Transform)
3737
.Concat(new[] {CallUndefined()})
3838
.ToArray();
39-
return new CallExpression(lx.IgnoreCase, lx.OperatorName, operands);
39+
return new CallExpression(call.IgnoreCase, call.OperatorName, operands);
4040
}
4141

42-
if (Operators.SameOperator(lx.OperatorName, Operators.OpCoalesce))
42+
if (Operators.SameOperator(call.OperatorName, Operators.OpCoalesce))
4343
{
44-
if (lx.Operands.Length == 0)
44+
if (call.Operands.Length == 0)
4545
return CallUndefined();
46-
if (lx.Operands.Length == 1)
47-
return Transform(lx.Operands.Single());
48-
if (lx.Operands.Length > 2)
46+
if (call.Operands.Length == 1)
47+
return Transform(call.Operands.Single());
48+
if (call.Operands.Length > 2)
4949
{
50-
var first = Transform(lx.Operands.First());
51-
return new CallExpression(lx.IgnoreCase, lx.OperatorName, first,
52-
Transform(new CallExpression(lx.IgnoreCase, lx.OperatorName, lx.Operands.Skip(1).ToArray())));
50+
var first = Transform(call.Operands.First());
51+
return new CallExpression(call.IgnoreCase, call.OperatorName, first,
52+
Transform(new CallExpression(call.IgnoreCase, call.OperatorName, call.Operands.Skip(1).ToArray())));
5353
}
5454
}
5555

56-
if (Operators.SameOperator(lx.OperatorName, Operators.OpToString) &&
57-
lx.Operands.Length == 1)
56+
if (Operators.SameOperator(call.OperatorName, Operators.OpToString) &&
57+
call.Operands.Length == 1)
5858
{
59-
return new CallExpression(lx.IgnoreCase, lx.OperatorName, lx.Operands[0], CallUndefined());
59+
return new CallExpression(call.IgnoreCase, call.OperatorName, call.Operands[0], CallUndefined());
6060
}
6161

62-
return base.Transform(lx);
62+
return base.Transform(call);
6363
}
6464

6565
static CallExpression CallUndefined()

src/Serilog.Expressions/Expressions/Compilation/Wildcards/WildcardSearch.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,14 @@ class WildcardSearch : SerilogExpressionTransformer<IndexerExpression?>
7676
return null;
7777
}
7878

79-
protected override IndexerExpression? Transform(CallExpression lx)
79+
protected override IndexerExpression? Transform(CallExpression call)
8080
{
8181
// If we hit a wildcard-compatible operation, then any wildcards within its operands "belong" to
8282
// it and can't be the result of this search.
83-
if (Operators.WildcardComparators.Contains(lx.OperatorName))
83+
if (Operators.WildcardComparators.Contains(call.OperatorName))
8484
return null;
8585

86-
return lx.Operands.Select(Transform).FirstOrDefault(e => e != null);
86+
return call.Operands.Select(Transform).FirstOrDefault(e => e != null);
8787
}
8888

8989
protected override IndexerExpression? Transform(IndexOfMatchExpression mx)

0 commit comments

Comments
 (0)