Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

4.0.0 Release #106

Merged
merged 13 commits into from
Nov 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion example/Sample/Sample.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
</ItemGroup>

<ItemGroup>
Expand Down
2 changes: 2 additions & 0 deletions src/Serilog.Expressions/Expressions/BuiltInProperty.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,6 @@ static class BuiltInProperty
public const string Properties = "p";
public const string Renderings = "r";
public const string EventId = "i";
public const string TraceId = "tr";
public const string SpanId = "sp";
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,10 @@ public ExpressionConstantMapper(IDictionary<object, Expression> mapping)

protected override Expression VisitConstant(ConstantExpression node)
{
if (node.Value != null &&
node.Value is ScalarValue sv &&
_mapping.TryGetValue(sv.Value, out var substitute))
if (node.Value is ScalarValue { Value: {} sv } &&
_mapping.TryGetValue(sv, out var substitute))
return substitute;

return base.VisitConstant(node);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ static class Intrinsics
public static LogEventPropertyValue ConstructSequenceValue(List<LogEventPropertyValue?> elements)
{
if (elements.Any(el => el == null))
return new SequenceValue(elements.Where(el => el != null));
return new SequenceValue(elements.Where(el => el != null)!);

return new SequenceValue(elements);
return new SequenceValue(elements!);
}

public static List<LogEventProperty> CollectStructureProperties(string[] names, LogEventPropertyValue?[] values)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,9 +186,8 @@ static ExpressionBody CompileLogical(Func<ExpressionBody, ExpressionBody, Expres
protected override ExpressionBody Transform(AccessorExpression spx)
{
var receiver = Transform(spx.Receiver);
return LX.Call(TryGetStructurePropertyValueMethod, LX.Constant(StringComparison.OrdinalIgnoreCase), receiver, LX.Constant(spx.MemberName, typeof(string)));
return LX.Call(TryGetStructurePropertyValueMethod, LX.Constant(StringComparison.Ordinal), receiver, LX.Constant(spx.MemberName, typeof(string)));
}

protected override ExpressionBody Transform(ConstantExpression cx)
{
return LX.Constant(cx.Constant);
Expand All @@ -207,6 +206,10 @@ protected override ExpressionBody Transform(AmbientNameExpression px)
BuiltInProperty.Message => Splice(context => new ScalarValue(Intrinsics.RenderMessage(formatter, context))),
BuiltInProperty.Exception => Splice(context =>
context.LogEvent.Exception == null ? null : new ScalarValue(context.LogEvent.Exception)),
BuiltInProperty.TraceId => Splice(context =>
context.LogEvent.TraceId == null ? null : new ScalarValue(context.LogEvent.TraceId.Value)),
BuiltInProperty.SpanId => Splice(context =>
context.LogEvent.SpanId == null ? null : new ScalarValue(context.LogEvent.SpanId.Value)),
BuiltInProperty.Timestamp => Splice(context => new ScalarValue(context.LogEvent.Timestamp)),
BuiltInProperty.MessageTemplate => Splice(context => new ScalarValue(context.LogEvent.MessageTemplate.Text)),
BuiltInProperty.Properties => Splice(context =>
Expand Down
13 changes: 13 additions & 0 deletions src/Serilog.Expressions/Expressions/Runtime/Coerce.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using Serilog.Events;

Expand Down Expand Up @@ -77,6 +78,18 @@ public static bool String(LogEventPropertyValue? value, [MaybeNullWhen(false)] o
str = sv.Value.ToString()!;
return true;
}

if (sv.Value is ActivityTraceId traceId)
{
str = traceId.ToHexString();
return true;
}

if (sv.Value is ActivitySpanId spanId)
{
str = spanId.ToHexString();
return true;
}
}

str = default;
Expand Down
12 changes: 7 additions & 5 deletions src/Serilog.Expressions/Serilog.Expressions.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
<PropertyGroup>
<Description>An embeddable mini-language for filtering, enriching, and formatting Serilog
events, ideal for use with JSON or XML configuration.</Description>
<VersionPrefix>3.5.0</VersionPrefix>
<VersionPrefix>4.0.0</VersionPrefix>
<Authors>Serilog Contributors</Authors>
<TargetFrameworks>netstandard2.0;netstandard2.1;net5.0</TargetFrameworks>
<TargetFrameworks>netstandard2.1;netstandard2.0;net5.0;net6.0;net7.0</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<RootNamespace>Serilog</RootNamespace>
<PackageTags>serilog</PackageTags>
Expand All @@ -14,15 +14,17 @@
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
<RepositoryUrl>https://github.com/serilog/serilog-expressions</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageReadmeFile>README.md</PackageReadmeFile>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Serilog" Version="2.12.0" />
<PackageReference Include="Nullable" Version="1.3.0" PrivateAssets="All" />
<PackageReference Include="Serilog" Version="3.1.0" />
<PackageReference Include="Nullable" Version="1.3.1" PrivateAssets="All" />
</ItemGroup>

<ItemGroup>
<None Include="..\..\assets\icon.png" Pack="true" Visible="false" PackagePath="" />
<None Include="..\..\README.md" Pack="true" Visible="false" PackagePath="" />
</ItemGroup>

</Project>
28 changes: 15 additions & 13 deletions src/Serilog.Expressions/Templates/Compilation/TemplateCompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
using Serilog.Expressions.Ast;
using Serilog.Expressions.Compilation;
using Serilog.Templates.Ast;
using Serilog.Templates.Encoding;
using Serilog.Templates.Themes;

namespace Serilog.Templates.Compilation;
Expand All @@ -24,39 +25,40 @@ static class TemplateCompiler
{
public static CompiledTemplate Compile(Template template,
IFormatProvider? formatProvider, NameResolver nameResolver,
TemplateTheme theme)
TemplateTheme theme,
EncodedTemplateFactory encoder)
{
return template switch
{
LiteralText text => new CompiledLiteralText(text.Text, theme),
FormattedExpression { Expression: AmbientNameExpression { IsBuiltIn: true, PropertyName: BuiltInProperty.Level} } level => new CompiledLevelToken(
level.Format, level.Alignment, theme),
FormattedExpression { Expression: AmbientNameExpression { IsBuiltIn: true, PropertyName: BuiltInProperty.Level} } level =>
encoder.Wrap(new CompiledLevelToken(level.Format, level.Alignment, theme)),
FormattedExpression
{
Expression: AmbientNameExpression { IsBuiltIn: true, PropertyName: BuiltInProperty.Exception },
Alignment: null,
Format: null
} => new CompiledExceptionToken(theme),
} => encoder.Wrap(new CompiledExceptionToken(theme)),
FormattedExpression
{
Expression: AmbientNameExpression { IsBuiltIn: true, PropertyName: BuiltInProperty.Message },
Format: null
} message => new CompiledMessageToken(formatProvider, message.Alignment, theme),
FormattedExpression expression => new CompiledFormattedExpression(
} message => encoder.Wrap(new CompiledMessageToken(formatProvider, message.Alignment, theme)),
FormattedExpression expression => encoder.MakeCompiledFormattedExpression(
ExpressionCompiler.Compile(expression.Expression, formatProvider, nameResolver), expression.Format, expression.Alignment, formatProvider, theme),
TemplateBlock block => new CompiledTemplateBlock(block.Elements.Select(e => Compile(e, formatProvider, nameResolver, theme)).ToArray()),
TemplateBlock block => new CompiledTemplateBlock(block.Elements.Select(e => Compile(e, formatProvider, nameResolver, theme, encoder)).ToArray()),
Conditional conditional => new CompiledConditional(
ExpressionCompiler.Compile(conditional.Condition, formatProvider, nameResolver),
Compile(conditional.Consequent, formatProvider, nameResolver, theme),
conditional.Alternative == null ? null : Compile(conditional.Alternative, formatProvider, nameResolver, theme)),
Compile(conditional.Consequent, formatProvider, nameResolver, theme, encoder),
conditional.Alternative == null ? null : Compile(conditional.Alternative, formatProvider, nameResolver, theme, encoder)),
Repetition repetition => new CompiledRepetition(
ExpressionCompiler.Compile(repetition.Enumerable, formatProvider, nameResolver),
repetition.BindingNames.Length > 0 ? repetition.BindingNames[0] : null,
repetition.BindingNames.Length > 1 ? repetition.BindingNames[1] : null,
Compile(repetition.Body, formatProvider, nameResolver, theme),
repetition.Delimiter == null ? null : Compile(repetition.Delimiter, formatProvider, nameResolver, theme),
repetition.Alternative == null ? null : Compile(repetition.Alternative, formatProvider, nameResolver, theme)),
Compile(repetition.Body, formatProvider, nameResolver, theme, encoder),
repetition.Delimiter == null ? null : Compile(repetition.Delimiter, formatProvider, nameResolver, theme, encoder),
repetition.Alternative == null ? null : Compile(repetition.Alternative, formatProvider, nameResolver, theme, encoder)),
_ => throw new NotSupportedException()
};
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
using Serilog.Expressions.Runtime;
using Serilog.Templates.Ast;
using Serilog.Templates.Compilation.UnreferencedProperties;
using Serilog.Templates.Compilation.Unsafe;

namespace Serilog.Templates.Compilation;

Expand All @@ -27,7 +28,8 @@ public static NameResolver Build(NameResolver? additionalNameResolver, Template
var resolvers = new List<NameResolver>
{
new StaticMemberNameResolver(typeof(RuntimeOperators)),
new UnreferencedPropertiesFunction(template)
new UnreferencedPropertiesFunction(template),
new UnsafeOutputFunction()
};

if (additionalNameResolver != null)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright © Serilog Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using Serilog.Events;
using Serilog.Expressions;
using Serilog.Templates.Encoding;

namespace Serilog.Templates.Compilation.Unsafe;

/// <summary>
/// Marks an expression in a template as bypassing the output encoding mechanism.
/// </summary>
class UnsafeOutputFunction : NameResolver
{
const string FunctionName = "unsafe";

public override bool TryResolveFunctionName(string name, [MaybeNullWhen(false)] out MethodInfo implementation)
{
if (name.Equals(FunctionName, StringComparison.OrdinalIgnoreCase))
{
implementation = typeof(UnsafeOutputFunction).GetMethod(nameof(Implementation),
BindingFlags.Static | BindingFlags.Public)!;
return true;
}

implementation = null;
return false;
}

// By convention, built-in functions accept and return nullable values.
// ReSharper disable once ReturnTypeCanBeNotNullable
public static LogEventPropertyValue? Implementation(LogEventPropertyValue? inner)
{
return new ScalarValue(new PreEncodedValue(inner));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Serilog.Expressions;
using Serilog.Templates.Compilation;

namespace Serilog.Templates.Encoding
{
class EncodedCompiledTemplate : CompiledTemplate
{
readonly CompiledTemplate _inner;
readonly TemplateOutputEncoder _encoder;

public EncodedCompiledTemplate(CompiledTemplate inner, TemplateOutputEncoder encoder)
{
_inner = inner;
_encoder = encoder;
}

public override void Evaluate(EvaluationContext ctx, TextWriter output)
{
var buffer = new StringWriter(output.FormatProvider);
_inner.Evaluate(ctx, buffer);
var encoded = _encoder.Encode(buffer.ToString());
output.Write(encoded);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using Serilog.Expressions;
using Serilog.Parsing;
using Serilog.Templates.Compilation;
using Serilog.Templates.Themes;

namespace Serilog.Templates.Encoding
{
class EncodedTemplateFactory
{
readonly TemplateOutputEncoder? _encoder;

public EncodedTemplateFactory(TemplateOutputEncoder? encoder)
{
_encoder = encoder;
}

public CompiledTemplate Wrap(CompiledTemplate inner)
{
if (_encoder == null)
return inner;

return new EncodedCompiledTemplate(inner, _encoder);
}

public CompiledTemplate MakeCompiledFormattedExpression(Evaluatable expression, string? format, Alignment? alignment, IFormatProvider? formatProvider, TemplateTheme theme)
{
if (_encoder == null)
return new CompiledFormattedExpression(expression, format, alignment, formatProvider, theme);

return new EscapableEncodedCompiledFormattedExpression(expression, format, alignment, formatProvider, theme, _encoder);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using Serilog.Events;
using Serilog.Expressions;
using Serilog.Expressions.Runtime;
using Serilog.Parsing;
using Serilog.Templates.Compilation;
using Serilog.Templates.Themes;

namespace Serilog.Templates.Encoding
{
class EscapableEncodedCompiledFormattedExpression : CompiledTemplate
{
static int _nextSubstituteLocalNameSuffix;
readonly string _substituteLocalName = $"%sub{Interlocked.Increment(ref _nextSubstituteLocalNameSuffix)}";
readonly Evaluatable _expression;
readonly TemplateOutputEncoder _encoder;
readonly CompiledFormattedExpression _inner;

public EscapableEncodedCompiledFormattedExpression(Evaluatable expression, string? format, Alignment? alignment, IFormatProvider? formatProvider, TemplateTheme theme, TemplateOutputEncoder encoder)
{
_expression = expression;
_encoder = encoder;

// `expression` can't be passed through, because it may include calls to the `unsafe()` function (nested in arbitrary subexpressions) that
// need to be evaluated first. So, instead, we evaluate `expression` and unwrap the result of `unsafe`, placing the result in a local variable
// that the formatting expression we construct here can read from.
_inner = new CompiledFormattedExpression(GetSubstituteLocalValue, format, alignment, formatProvider, theme);
}

LogEventPropertyValue? GetSubstituteLocalValue(EvaluationContext context)
{
return Locals.TryGetValue(context.Locals, _substituteLocalName, out var computed)
? computed
: null;
}

public override void Evaluate(EvaluationContext ctx, TextWriter output)
{
var value = _expression(ctx);

if (value is ScalarValue { Value: PreEncodedValue pv })
{
var rawContext = pv.Inner == null ?
new EvaluationContext(ctx.LogEvent) :
new EvaluationContext(ctx.LogEvent, Locals.Set(ctx.Locals, _substituteLocalName, pv.Inner));
_inner.Evaluate(rawContext, output);
return;
}

var buffer = new StringWriter(output.FormatProvider);

var bufferedContext = value == null
? ctx
: new EvaluationContext(ctx.LogEvent, Locals.Set(ctx.Locals, _substituteLocalName, value));

_inner.Evaluate(bufferedContext, buffer);
var encoded = _encoder.Encode(buffer.ToString());
output.Write(encoded);
}
}
}
Loading