Repository: serilog/serilog-expressions
Branch: dev
Commit: 697c8fa89ec1
Files: 188
Total size: 526.8 KB
Directory structure:
gitextract_cw7ezsg_/
├── .gitattributes
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ ├── config.yml
│ │ └── feature_request.md
│ └── workflows/
│ └── ci.yml
├── .gitignore
├── Build.ps1
├── Directory.Build.props
├── Directory.Version.props
├── LICENSE
├── README.md
├── RunPerfTests.ps1
├── assets/
│ └── Serilog.snk
├── example/
│ └── Sample/
│ ├── Program.cs
│ └── Sample.csproj
├── global.json
├── serilog-expressions.sln
├── serilog-expressions.sln.DotSettings
├── src/
│ └── Serilog.Expressions/
│ ├── Expressions/
│ │ ├── Ast/
│ │ │ ├── AccessorExpression.cs
│ │ │ ├── AmbientNameExpression.cs
│ │ │ ├── ArrayExpression.cs
│ │ │ ├── CallExpression.cs
│ │ │ ├── ConstantExpression.cs
│ │ │ ├── Element.cs
│ │ │ ├── Expression.cs
│ │ │ ├── IndexOfMatchExpression.cs
│ │ │ ├── IndexerExpression.cs
│ │ │ ├── IndexerWildcard.cs
│ │ │ ├── IndexerWildcardExpression.cs
│ │ │ ├── ItemElement.cs
│ │ │ ├── LambdaExpression.cs
│ │ │ ├── LocalNameExpression.cs
│ │ │ ├── Member.cs
│ │ │ ├── ObjectExpression.cs
│ │ │ ├── ParameterExpression.cs
│ │ │ ├── PropertyMember.cs
│ │ │ ├── SpreadElement.cs
│ │ │ └── SpreadMember.cs
│ │ ├── BuiltInProperty.cs
│ │ ├── Compilation/
│ │ │ ├── Arrays/
│ │ │ │ └── ConstantArrayEvaluator.cs
│ │ │ ├── DefaultFunctionNameResolver.cs
│ │ │ ├── ExpressionCompiler.cs
│ │ │ ├── ExpressionValidationException.cs
│ │ │ ├── Linq/
│ │ │ │ ├── EventIdHash.cs
│ │ │ │ ├── ExpressionConstantMapper.cs
│ │ │ │ ├── Intrinsics.cs
│ │ │ │ ├── LinqExpressionCompiler.cs
│ │ │ │ └── ParameterReplacementVisitor.cs
│ │ │ ├── OrderedNameResolver.cs
│ │ │ ├── Pattern.cs
│ │ │ ├── Properties/
│ │ │ │ └── PropertiesObjectAccessorTransformer.cs
│ │ │ ├── Text/
│ │ │ │ ├── LikeSyntaxTransformer.cs
│ │ │ │ └── TextMatchingTransformer.cs
│ │ │ ├── Transformations/
│ │ │ │ ├── IdentityTransformer.cs
│ │ │ │ ├── NodeReplacer.cs
│ │ │ │ └── SerilogExpressionTransformer.cs
│ │ │ ├── Variadics/
│ │ │ │ └── VariadicCallRewriter.cs
│ │ │ └── Wildcards/
│ │ │ ├── WildcardComprehensionTransformer.cs
│ │ │ └── WildcardSearch.cs
│ │ ├── CompiledExpression.cs
│ │ ├── Evaluatable.cs
│ │ ├── EvaluationContext.cs
│ │ ├── ExpressionResult.cs
│ │ ├── Helpers.cs
│ │ ├── LoggingFilterSwitch.cs
│ │ ├── NameResolver.cs
│ │ ├── Operators.cs
│ │ ├── Parsing/
│ │ │ ├── Combinators.cs
│ │ │ ├── ExpressionKeyword.cs
│ │ │ ├── ExpressionParser.cs
│ │ │ ├── ExpressionTextParsers.cs
│ │ │ ├── ExpressionToken.cs
│ │ │ ├── ExpressionTokenParsers.cs
│ │ │ ├── ExpressionTokenizer.cs
│ │ │ └── ParserExtensions.cs
│ │ ├── Runtime/
│ │ │ ├── Coerce.cs
│ │ │ ├── Locals.cs
│ │ │ ├── RuntimeOperators.cs
│ │ │ └── Support/
│ │ │ └── UnflattenDottedPropertyNames.cs
│ │ ├── SerilogExpression.cs
│ │ └── StaticMemberNameResolver.cs
│ ├── LoggerEnrichmentConfigurationExtensions.cs
│ ├── LoggerFilterConfigurationExtensions.cs
│ ├── LoggerSinkConfigurationExtensions.cs
│ ├── ParserConstruction/
│ │ ├── Combinators.cs
│ │ ├── Display/
│ │ │ ├── Presentation.cs
│ │ │ └── TokenAttribute.cs
│ │ ├── Model/
│ │ │ ├── Position.cs
│ │ │ ├── Result.cs
│ │ │ ├── Result`1.cs
│ │ │ ├── TextSpan.cs
│ │ │ ├── TokenListParserResult.cs
│ │ │ ├── TokenListParserResult`2.cs
│ │ │ ├── TokenList`1.cs
│ │ │ ├── Token`1.cs
│ │ │ └── Unit.cs
│ │ ├── Parse.cs
│ │ ├── ParseException.cs
│ │ ├── ParserExtensions.cs
│ │ ├── Parsers/
│ │ │ ├── Character.cs
│ │ │ ├── Numerics.cs
│ │ │ ├── Span.cs
│ │ │ └── Token.cs
│ │ ├── README.md
│ │ ├── TextParser`1.cs
│ │ ├── TokenListParser`2.cs
│ │ ├── Tokenizer`1.cs
│ │ └── Util/
│ │ ├── CharInfo.cs
│ │ └── Friendly.cs
│ ├── Pipeline/
│ │ └── ComputedPropertyEnricher.cs
│ ├── Properties/
│ │ └── AssemblyInfo.cs
│ ├── Serilog.Expressions.csproj
│ └── Templates/
│ ├── Ast/
│ │ ├── Conditional.cs
│ │ ├── FormattedExpression.cs
│ │ ├── LiteralText.cs
│ │ ├── Repetition.cs
│ │ ├── Template.cs
│ │ └── TemplateBlock.cs
│ ├── Compilation/
│ │ ├── CompiledConditional.cs
│ │ ├── CompiledExceptionToken.cs
│ │ ├── CompiledFormattedExpression.cs
│ │ ├── CompiledLevelToken.cs
│ │ ├── CompiledLiteralText.cs
│ │ ├── CompiledMessageToken.cs
│ │ ├── CompiledRepetition.cs
│ │ ├── CompiledTemplate.cs
│ │ ├── CompiledTemplateBlock.cs
│ │ ├── CompiledTimestampToken.cs
│ │ ├── NameResolution/
│ │ │ ├── ExpressionLocalNameBinder.cs
│ │ │ └── TemplateLocalNameBinder.cs
│ │ ├── TemplateCompiler.cs
│ │ ├── TemplateFunctionNameResolver.cs
│ │ ├── UnreferencedProperties/
│ │ │ ├── ExpressionReferencedPropertiesFinder.cs
│ │ │ ├── TemplateReferencedPropertiesFinder.cs
│ │ │ └── UnreferencedPropertiesFunction.cs
│ │ └── Unsafe/
│ │ └── UnsafeOutputFunction.cs
│ ├── Encoding/
│ │ ├── EncodedCompiledTemplate.cs
│ │ ├── EncodedTemplateFactory.cs
│ │ ├── EscapableEncodedCompiledFormattedExpression.cs
│ │ ├── PreEncodedValue.cs
│ │ └── TemplateOutputEncoder.cs
│ ├── ExpressionTemplate.cs
│ ├── Parsing/
│ │ ├── TemplateParser.cs
│ │ ├── TemplateTokenParsers.cs
│ │ └── TemplateTokenizer.cs
│ ├── Rendering/
│ │ ├── AlignmentExtensions.cs
│ │ ├── Casing.cs
│ │ ├── LevelRenderer.cs
│ │ └── Padding.cs
│ └── Themes/
│ ├── Style.cs
│ ├── StyleReset.cs
│ ├── TemplateTheme.cs
│ ├── TemplateThemeStyle.cs
│ ├── TemplateThemes.cs
│ └── ThemedJsonValueFormatter.cs
└── test/
├── Serilog.Expressions.PerformanceTests/
│ ├── ComparisonBenchmark.cs
│ ├── Harness.cs
│ ├── Serilog.Expressions.PerformanceTests.csproj
│ └── Support/
│ └── Some.cs
└── Serilog.Expressions.Tests/
├── Cases/
│ ├── expression-evaluation-cases.asv
│ ├── template-encoding-cases.asv
│ ├── template-evaluation-cases.asv
│ └── translation-cases.asv
├── ConfigurationTests.cs
├── ExpressionCompilerTests.cs
├── ExpressionEvaluationTests.cs
├── ExpressionParserTests.cs
├── ExpressionTranslationTests.cs
├── ExpressionValidationTests.cs
├── ExpressionValueTests.cs
├── Expressions/
│ ├── NameResolverTests.cs
│ └── Runtime/
│ ├── LocalsTests.cs
│ └── RuntimeOperatorsTests.cs
├── FormatParityTests.cs
├── LoggingFilterSwitchTests.cs
├── Properties/
│ └── launchSettings.json
├── Serilog.Expressions.Tests.csproj
├── Support/
│ ├── AsvCases.cs
│ ├── CollectingSink.cs
│ ├── ParenthesizingEncoder.cs
│ ├── Some.cs
│ ├── StringHashPrefixingTheme.cs
│ └── TestHelperNameResolver.cs
├── TemplateEncodingTests.cs
├── TemplateEvaluationTests.cs
├── TemplateParserTests.cs
├── TemplateTokenizerTests.cs
└── Templates/
└── UnreferencedPropertiesFunctionTests.cs
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
# Auto detect text files and perform LF normalization
* text=auto
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Report a bug and help us to improve Serilog.Expressions
title: ''
labels: bug
assignees: ''
---
The Serilog maintainers want you to have a great experience using Serilog.Expressions, and will happily track down and resolve bugs. We all have limited time, though, so please think through all of the factors that might be involved and include as much useful information as possible 😊.
ℹ If the problem is caused by a sink or other extension package, please track down the correct repository for that package and create the report there: this tracker is for the **Serilog.Expressions** package only.
**Description**
What's going wrong?
**Reproduction**
Please provide code samples showing how you're configuring and calling Serilog.Expressions to produce the behavior.
**Expected behavior**
A concise description of what you expected to happen.
**Relevant package, tooling and runtime versions**
What Serilog version are you using, on what platform?
**Additional context**
Add any other context about the problem here.
================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
contact_links:
- name: Ask for help
url: https://stackoverflow.com/tags/serilog
about: Ask the community for help on how to use Serilog.Expressions
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an improvement to Serilog.Expressions
title: ''
labels: enhancement
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. For example, "I'd like to do _x_ but currently I can't because _y_ [...]".
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any workarounds or alternative solutions you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
================================================
FILE: .github/workflows/ci.yml
================================================
# If this file is renamed, the incrementing run attempt number will be reset.
name: CI
on:
push:
branches: [ "dev", "main" ]
pull_request:
branches: [ "dev", "main" ]
env:
CI_BUILD_NUMBER_BASE: ${{ github.run_number }}
CI_TARGET_BRANCH: ${{ github.head_ref || github.ref_name }}
jobs:
build:
# The build must run on Windows so that .NET Framework targets can be built and tested.
runs-on: windows-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- name: Setup
uses: actions/setup-dotnet@v4
with:
dotnet-version: 9.0.x
- name: Compute build number
shell: bash
run: |
echo "CI_BUILD_NUMBER=$(($CI_BUILD_NUMBER_BASE+2300))" >> $GITHUB_ENV
- name: Build and Publish
env:
DOTNET_CLI_TELEMETRY_OPTOUT: true
NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
shell: pwsh
run: |
./Build.ps1
================================================
FILE: .gitignore
================================================
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
.idea
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# DNX
project.lock.json
artifacts/
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignoreable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Microsoft Azure ApplicationInsights config file
ApplicationInsights.config
# Windows Store app package directory
AppPackages/
BundleArtifacts/
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.pfx
*.publishsettings
node_modules/
orleans.codegen.cs
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
# FAKE - F# Make
.fake/
example/Sample/log.txt
BenchmarkDotNet.Artifacts/
================================================
FILE: Build.ps1
================================================
Write-Output "build: Tool versions follow"
dotnet --version
dotnet --list-sdks
Write-Output "build: Build started"
Push-Location $PSScriptRoot
try {
if(Test-Path .\artifacts) {
Write-Output "build: Cleaning ./artifacts"
Remove-Item ./artifacts -Force -Recurse
}
& dotnet restore --no-cache
$dbp = [Xml] (Get-Content .\Directory.Version.props)
$versionPrefix = $dbp.Project.PropertyGroup.VersionPrefix
Write-Output "build: Package version prefix is $versionPrefix"
$branch = @{ $true = $env:CI_TARGET_BRANCH; $false = $(git symbolic-ref --short -q HEAD) }[$NULL -ne $env:CI_TARGET_BRANCH];
$revision = @{ $true = "{0:00000}" -f [convert]::ToInt32("0" + $env:CI_BUILD_NUMBER, 10); $false = "local" }[$NULL -ne $env:CI_BUILD_NUMBER];
$suffix = @{ $true = ""; $false = "$($branch.Substring(0, [math]::Min(10,$branch.Length)) -replace '([^a-zA-Z0-9\-]*)', '')-$revision"}[$branch -eq "main" -and $revision -ne "local"]
$commitHash = $(git rev-parse --short HEAD)
$buildSuffix = @{ $true = "$($suffix)-$($commitHash)"; $false = "$($branch)-$($commitHash)" }[$suffix -ne ""]
Write-Output "build: Package version suffix is $suffix"
Write-Output "build: Build version suffix is $buildSuffix"
& dotnet build -c Release --version-suffix=$buildSuffix /p:ContinuousIntegrationBuild=true
if($LASTEXITCODE -ne 0) { throw "Build failed" }
foreach ($src in Get-ChildItem src/*) {
Push-Location $src
Write-Output "build: Packaging project in $src"
if ($suffix) {
& dotnet pack -c Release --no-build --no-restore -o ../../artifacts --version-suffix=$suffix
} else {
& dotnet pack -c Release --no-build --no-restore -o ../../artifacts
}
if($LASTEXITCODE -ne 0) { throw "Packaging failed" }
Pop-Location
}
foreach ($test in Get-ChildItem test/*.Tests) {
Push-Location $test
Write-Output "build: Testing project in $test"
& dotnet test -c Release --no-build --no-restore
if($LASTEXITCODE -ne 0) { throw "Testing failed" }
Pop-Location
}
if ($env:NUGET_API_KEY) {
# GitHub Actions will only supply this to branch builds and not PRs. We publish
# builds from any branch this action targets (i.e. main and dev).
Write-Output "build: Publishing NuGet packages"
foreach ($nupkg in Get-ChildItem artifacts/*.nupkg) {
& dotnet nuget push -k $env:NUGET_API_KEY -s https://api.nuget.org/v3/index.json "$nupkg"
if($LASTEXITCODE -ne 0) { throw "Publishing failed" }
}
if (!($suffix)) {
Write-Output "build: Creating release for version $versionPrefix"
iex "gh release create v$versionPrefix --title v$versionPrefix --generate-notes $(get-item ./artifacts/*.nupkg) $(get-item ./artifacts/*.snupkg)"
}
}
} finally {
Pop-Location
}
================================================
FILE: Directory.Build.props
================================================
latest
True
true
$(MSBuildThisFileDirectory)assets/Serilog.snk
false
enable
enable
true
true
true
true
snupkg
================================================
FILE: Directory.Version.props
================================================
5.1.0
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.
================================================
FILE: README.md
================================================
# Serilog.Expressions [](https://github.com/serilog/serilog-expressions/actions) [](https://nuget.org/packages/serilog.expressions)
An embeddable mini-language for filtering, enriching, and formatting Serilog
events, ideal for use with JSON or XML configuration.
## Getting started
Install the package from NuGet:
```shell
dotnet add package Serilog.Expressions
```
The package adds extension methods to Serilog's `Filter`, `WriteTo`, and
`Enrich` configuration objects, along with an `ExpressionTemplate`
type that's compatible with Serilog sinks accepting an
`ITextFormatter`.
### Filtering example
_Serilog.Expressions_ adds `ByExcluding()` and `ByIncludingOnly()`
overloads to the `Filter` configuration object that accept filter
expressions:
```csharp
Log.Logger = new LoggerConfiguration()
.Filter.ByExcluding("RequestPath like '/health%'")
.CreateLogger();
```
Events with a `RequestPath` property that matches the expression
will be excluded by the filter.
> Note that if the expression syntax is invalid, an `ArgumentException` will
be thrown from the `ByExcluding()` method, and by similar methods elsewhere
in the package. To check expression syntax without throwing, see the
`Try*()` methods in the `SerilogExpression` class.
#### An `appSettings.json` JSON configuration example
In [`appSettings.json` configuration](https://github.com/serilog/serilog-settings-configuration)
this is written as:
```json
{
"Serilog": {
"Using": ["Serilog.Expressions"],
"Filter": [
{
"Name": "ByExcluding",
"Args": {
"expression": "RequestPath like '/health%'"
}
}
]
}
}
```
#### An `` XML configuration example
In [XML configuration files](https://github.com/serilog/serilog-settings-appsettings),
this is written as:
```xml
```
## Supported configuration APIs
_Serilog.Expressions_ adds a number of expression-based overloads and helper methods to the Serilog configuration syntax:
* `Filter.ByExcluding()`, `Filter.ByIncludingOnly()` - use an expression to filter events passing through the Serilog pipeline
* `WriteTo.Conditional()` - use an expression to select the events passed to a particular sink
* `Enrich.When()` - conditionally enable an enricher when events match an expression
* `Enrich.WithComputed()` - add or modify event properties using an expression
## Formatting with `ExpressionTemplate`
_Serilog.Expressions_ includes the `ExpressionTemplate` class for text formatting. `ExpressionTemplate` implements `ITextFormatter`, so
it works with any text-based Serilog sink, including `Console`, `File`, `Debug`, and `Email`:
```csharp
// using Serilog.Templates;
Log.Logger = new LoggerConfiguration()
.WriteTo.Console(new ExpressionTemplate(
"[{@t:HH:mm:ss} {@l:u3} ({SourceContext})] {@m} (first item is {Cart[0]})\n{@x}"))
.CreateLogger();
// Produces log events like:
// [21:21:40 INF (Sample.Program)] Cart contains ["Tea","Coffee"] (first item is Tea)
```
Templates are based on .NET format strings, and support standard padding, alignment, and format specifiers.
Along with standard properties for the event timestamp (`@t`), level (`@l`) and so on, "holes" in expression templates can include complex
expressions over the first-class properties of the event, like `{SourceContext}` and `{Cart[0]}` in the example..
Templates support customizable color themes when used with the `Console` sink:
```csharp
.WriteTo.Console(new ExpressionTemplate(
"[{@t:HH:mm:ss} {@l:u3}] {@m}\n{@x}", theme: TemplateTheme.Code))
```

Newline-delimited JSON (for example, replicating the [CLEF format](https://github.com/serilog/serilog-formatting-compact)) can be generated
using object literals:
```csharp
.WriteTo.Console(new ExpressionTemplate(
"{ {@t, @mt, @r, @l: if @l = 'Information' then undefined() else @l, @x, ..@p} }\n"))
```
## Language reference
### Properties
The following properties are available in expressions:
* **All first-class properties of the event** - no special syntax: `SourceContext` and `Cart` are used in the formatting examples above
* `@t` - the event's timestamp, as a `DateTimeOffset`
* `@m` - the rendered message (Note: do not add format specifiers like `:lj` or you'll lose theme color rendering. These format specifiers are not supported as they've become the default and only option - [see the discussion here](https://github.com/serilog/serilog-expressions/issues/56#issuecomment-1146472988)
* `@mt` - the raw message template
* `@l` - the event's level, as a `LogEventLevel`
* `@x` - the exception associated with the event, if any, as an `Exception`
* `@p` - a dictionary containing all first-class properties; this supports properties with non-identifier names, for example `@p['snake-case-name']`
* `@i` - event id; a 32-bit numeric hash of the event's message template
* `@r` - renderings; if any tokens in the message template include .NET-specific formatting, an array of rendered values for each such token
* `@tr` - trace id; The id of the trace that was active when the event was created, if any
* `@sp` - span id; The id of the span that was active when the event was created, if any
The built-in properties mirror those available in the CLEF format.
The exception property `@x` is treated as a scalar and will appear as a string when formatted into text. The properties of
the underlying `Exception` object can be accessed using `Inspect()`, for example `Inspect(@x).Message`, and the type of the
exception retrieved using `TypeOf(@x)`.
### Literals
| Data type | Description | Examples |
| :--- | :--- | :--- |
| Null | Corresponds to .NET's `null` value | `null` |
| Number | A number in decimal or hexadecimal notation, represented by .NET `decimal` | `0`, `100`, `-12.34`, `0xC0FFEE` |
| String | A single-quoted Unicode string literal; to escape `'`, double it | `'pie'`, `'isn''t'`, `'😋'` |
| Boolean | A Boolean value | `true`, `false` |
| Array | An array of values, in square brackets | `[1, 'two', null]` |
| Object | A mapping of string keys to values; keys that are valid identifiers do not need to be quoted | `{a: 1, 'b c': 2, d}` |
Array and object literals support the spread operator: `[1, 2, ..others]`, `{a: 1, ..others}`. Specifying an undefined
property in an object literal will remove it from the result: `{..User, Email: Undefined()}`
### Operators and conditionals
A typical set of operators is supported:
* Equality `=` and inequality `<>`, including for arrays and objects
* Boolean `and`, `or`, `not`
* Arithmetic `+`, `-`, `*`, `/`, `^`, `%`
* Numeric comparison `<`, `<=`, `>`, `>=`
* Existence `is null` and `is not null`
* SQL-style `like` and `not like`, with `%` and `_` wildcards (double wildcards to escape them)
* Array membership with `in` and `not in`
* Accessors `a.b`
* Indexers `a['b']` and `a[0]`
* Wildcard indexing - `a[?]` any, and `a[*]` all
* Conditional `if a then b else c` (all branches required; see also the section below on _conditional blocks_)
Comparision operators that act on text all accept an optional postfix `ci` modifier to select case-insensitive comparisons:
```
User.Name like 'n%' ci
```
### Functions
Functions are called using typical `Identifier(args)` syntax.
Except for the `IsDefined()` function, the result of
calling a function will be undefined if:
* any argument is undefined, or
* any argument is of an incompatible type.
| Function | Description |
|:--------------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `Coalesce(a0, a1, [..aN])` | Returns the first defined, non-null argument. |
| `Concat(s0, s1, [..sN])` | Concatenate two or more strings. |
| `Contains(s, p)` | Tests whether the string `s` contains the substring `p`. |
| `ElementAt(x, i)` | Retrieves a property of `x` by name `i`, or array element of `x` by numeric index `i`. |
| `EndsWith(s, p)` | Tests whether the string `s` ends with substring `p`. |
| `IndexOf(s, p)` | Returns the first index of substring `p` in string `s`, or -1 if the substring does not appear. |
| `IndexOfMatch(s, p)` | Returns the index of the first match of regular expression `p` in string `s`, or -1 if the regular expression does not match. |
| `Inspect(o, [deep])` | Read properties from an object captured as the scalar value `o`. |
| `IsMatch(s, p)` | Tests whether the regular expression `p` matches within the string `s`. |
| `IsDefined(x)` | Returns `true` if the expression `x` has a value, including `null`, or `false` if `x` is undefined. |
| `LastIndexOf(s, p)` | Returns the last index of substring `p` in string `s`, or -1 if the substring does not appear. |
| `Length(x)` | Returns the length of a string or array. |
| `Nest(o)` | Converts dotted (flattened) property names of object `o` into nested sub-objects. |
| `Now()` | Returns `DateTimeOffset.Now`. |
| `Replace(s, p, r)` | Replace occurrences of substring `p` in string `s` with replacement `r`. |
| `Rest([deep])` | In an `ExpressionTemplate`, returns an object containing the first-class event properties not otherwise referenced in the template. If `deep` is `true`, also excludes properties referenced in the event's message template. |
| `Round(n, m)` | Round the number `n` to `m` decimal places. |
| `StartsWith(s, p)` | Tests whether the string `s` starts with substring `p`. |
| `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. |
| `TagOf(o)` | Returns the `TypeTag` field of a captured object (i.e. where `TypeOf(x)` is `'object'`). |
| `ToString(x, [format])` | Convert `x` to a string, applying the format string `format` if `x` is `IFormattable`. |
| `TypeOf(x)` | Returns a string describing the type of expression `x`: a .NET type name if `x` is scalar and non-null, or, `'array'`, `'object'`, `'dictionary'`, `'null'`, or `'undefined'`. |
| `Undefined()` | Explicitly mark an undefined value. |
| `UtcDateTime(x)` | Convert a `DateTime` or `DateTimeOffset` into a UTC `DateTime`. |
Functions that compare text accept an optional postfix `ci` modifier to select case-insensitive comparisons:
```
StartsWith(User.Name, 'n') ci
```
### Template directives
#### Conditional blocks
Within an `ExpressionTemplate`, a portion of the template can be conditionally evaluated using `#if`.
```csharp
Log.Logger = new LoggerConfiguration()
.WriteTo.Console(new ExpressionTemplate(
"[{@t:HH:mm:ss} {@l:u3}{#if SourceContext is not null} ({SourceContext}){#end}] {@m}\n{@x}"))
.CreateLogger();
// Produces log events like:
// [21:21:45 INF] Starting up
// [21:21:46 INF (Sample.Program)] Firing engines
```
The block between the `{#if }` and `{#end}` directives will only appear in the output if `` is `true` - in the example, events with a `SourceContext` include this in parentheses, while those without, don't.
It's important to notice that the directive requires a Boolean `true` before the conditional block will be evaluated. It wouldn't be sufficient in this case to write `{#if SourceContext}`, since no values other than `true` are considered "truthy".
The syntax supports `{#if }`, chained `{#else if }`, `{#else}`, and `{#end}`, with arbitrary nesting.
#### Repetition
If a log event includes structured data in arrays or objects, a template block can be repeated for each element or member using `#each`/`in` (newlines, double quotes and construction of the `ExpressionTemplate` omitted for clarity):
```
{@l:w4}: {SourceContext}
{#each s in Scope}=> {s}{#delimit} {#end}
{@m}
{@x}
```
This example uses the optional `#delimit` to add a space between each element, producing output like:
```
info: Sample.Program
=> Main => TextFormattingExample
Hello, world!
```
When using `{#each in }` over an object, such as the built-in `@p` (properties) object, `` will be bound to the _names_ of the properties of the object.
To get to the _values_ of the properties, use a second binding:
```
{#each k, v in @p}{k} = {v}{#delimit},{#end}
```
This example, if an event has three properties, will produce output like:
```
Account = "nblumhardt", Cart = ["Tea", "Coffee"], Powerup = 42
```
The syntax supports `{#each [, ] in }`, an optional `{#delimit}` block, and finally an optional `{#else}` block, which will be evaluated if the array or object is empty.
## Recipes
**Trim down `SourceContext` to a type name only:**
```
Substring(SourceContext, LastIndexOf(SourceContext, '.') + 1)
```
This expression takes advantage of `LastIndexOf()` returning -1 when no `.` character appears in `SourceContext`, to yield a `startIndex` of 0 in that case.
**Write not-referenced context properties (only if there are any):**
```
{#if rest(true) <> {}} {#end}
```
**Access a property with a non-identifier name:**
```
@p['some name']
```
Any structured value, including the built-in `@p`, can be indexed by string key. This means that `User.Name` and `User['Name']` are equivalent, for example.
**Access a property with inconsistent casing:**
```
ElementAt(@p, 'someName') ci
```
`ElementAt()` is a function-call version of the `[]` indexer notation, which means it can accept the `ci` case-insensitivity modifier.
**Format events as newline-delimited JSON (template, embedded in C# or JSON):**
```
{ {Timestamp: @t, Username: User.Name} }\n
```
This output template shows the use of a space between the opening `{` of a hole, and the enclosed object literal with `Timestamp` and
`Username` fields. The object will be formatted as JSON. The trailing `\n` is a C# or JSON newline literal (don't escape this any further, as
it's not part of the output template syntax).
## Working with the raw API
The package provides the class `SerilogExpression` in the `Serilog.Expressions` namespace
for working with expressions.
```csharp
if (SerilogExpression.TryCompile("RequestPath like '/health%'", out var compiled, out var error)
{
// `compiled` is a function that can be executed against `LogEvent`s:
var result = compiled(someEvent);
// `result` will contain a `LogEventPropertyValue`, or `null` if the result of evaluating the
// expression is undefined (for example if the event has no `RequestPath` property).
if (result is ScalarValue value &&
value.Value is bool matches &&
matches)
{
Console.WriteLine("The event matched.");
}
}
else
{
// `error` describes a syntax error.
Console.WriteLine($"Couldn't compile the expression; {error}.");
}
```
Compiled expression delegates return `LogEventPropertyValue` because this is the most
convenient type to work with in many Serilog scenarios (enrichers, sinks, ...). To
convert the result to plain-old-.NET-types like `string`, `bool`, `Dictionary` and
`Array`, use the functions in the `Serilog.Expressions.ExpressionResult` class:
```csharp
var result = compiled(someEvent);
// `true` only if `result` is a scalar Boolean `true`; `false` otherwise:
if (ExpressionResult.IsTrue(result))
{
Console.WriteLine("The event matched.");
}
```
## Implementing user-defined functions
User-defined functions can be plugged in by implementing static methods that:
* Return `LogEventPropertyValue?`,
* Have arguments of type `LogEventPropertyValue?` or `LogEvent`,
* If the `ci` modifier is supported, accept a `StringComparison`, and
* If culture-specific formatting or comparisons are used, accepts an `IFormatProvider`.
For example:
```csharp
public static class MyFunctions
{
public static LogEventPropertyValue? IsHello(
StringComparison comparison,
LogEventPropertyValue? maybeHello)
{
if (maybeHello is ScalarValue sv && sv.Value is string s)
return new ScalarValue(s.Equals("Hello", comparison));
// Undefined - argument was not a string.
return null;
}
}
```
In the example, `IsHello('Hello')` will evaluate to `true`, `IsHello('HELLO')` will be `false`, `IsHello('HELLO') ci`
will be `true`, and `IsHello(42)` will be undefined.
User-defined functions are supplied through an instance of `NameResolver`:
```csharp
var myFunctions = new StaticMemberNameResolver(typeof(MyFunctions));
var expr = SerilogExpression.Compile("IsHello(User.Name)", nameResolver: myFunctions);
// Filter events based on whether `User.Name` is `'Hello'` :-)
```
## Acknowledgements
Includes the parser combinator implementation from [Superpower](https://github.com/datalust/superpower), copyright Datalust,
Superpower Contributors, and Sprache Contributors; licensed under the Apache License, 2.0.
================================================
FILE: RunPerfTests.ps1
================================================
Push-Location $PSScriptRoot
./Build.ps1
foreach ($test in ls test/*.PerformanceTests) {
Push-Location $test
echo "perf: Running performance test project in $test"
& dotnet test -c Release
if($LASTEXITCODE -ne 0) { exit 2 }
Pop-Location
}
Pop-Location
================================================
FILE: example/Sample/Program.cs
================================================
using Serilog;
using Serilog.Debugging;
using Serilog.Templates;
using Serilog.Templates.Themes;
SelfLog.Enable(Console.Error);
TextFormattingExample1();
JsonFormattingExample();
PipelineComponentExample();
TextFormattingExample2();
return;
static void TextFormattingExample1()
{
using var log = new LoggerConfiguration()
.Enrich.WithProperty("Application", "Sample")
.WriteTo.Console(new ExpressionTemplate(
"[{@t:HH:mm:ss} {@l:u3}" +
"{#if SourceContext is not null} ({Substring(SourceContext, LastIndexOf(SourceContext, '.') + 1)}){#end}] " +
"{@m} (first item is {coalesce(Items[0], '')}) {rest()}\n{@x}",
theme: TemplateTheme.Code))
.CreateLogger();
log.Information("Running {Example}", nameof(TextFormattingExample1));
log.ForContext()
.Information("Cart contains {@Items}", new[] { "Tea", "Coffee" });
log.ForContext()
.Information("Cart contains {@Items}", new[] { "Apricots" });
}
static void JsonFormattingExample()
{
using var log = new LoggerConfiguration()
.Enrich.WithProperty("Application", "Example")
.WriteTo.Console(new ExpressionTemplate(
"{ {@t: UtcDateTime(@t), @mt, @l: if @l = 'Information' then undefined() else @l, @x, ..@p} }\n"))
.CreateLogger();
log.Information("Running {Example}", nameof(JsonFormattingExample));
log.ForContext()
.Information("Cart contains {@Items}", new[] { "Tea", "Coffee" });
log.ForContext()
.Warning("Cart is empty");
}
static void PipelineComponentExample()
{
using var log = new LoggerConfiguration()
.Enrich.WithProperty("Application", "Example")
.Enrich.WithComputed("FirstItem", "coalesce(Items[0], '')")
.Enrich.WithComputed("SourceContext", "coalesce(Substring(SourceContext, LastIndexOf(SourceContext, '.') + 1), '')")
.Filter.ByIncludingOnly("Items is null or Items[?] like 'C%'")
.WriteTo.Console(outputTemplate:
"[{Timestamp:HH:mm:ss} {Level:u3} ({SourceContext})] {Message:lj} (first item is {FirstItem}){NewLine}{Exception}")
.CreateLogger();
log.Information("Running {Example}", nameof(PipelineComponentExample));
log.ForContext()
.Information("Cart contains {@Items}", new[] { "Tea", "Coffee" });
log.ForContext()
.Information("Cart contains {@Items}", new[] { "Apricots" });
}
static void TextFormattingExample2()
{
// Emulates `Microsoft.Extensions.Logging`'s `ConsoleLogger`.
var melon = new TemplateTheme(TemplateTheme.Literate, new Dictionary
{
// `Information` is dark green in MEL.
[TemplateThemeStyle.LevelInformation] = "\x1b[38;5;34m",
[TemplateThemeStyle.String] = "\x1b[38;5;159m",
[TemplateThemeStyle.Number] = "\x1b[38;5;159m"
});
using var log = new LoggerConfiguration()
.WriteTo.Console(new ExpressionTemplate(
"{@l:w4}: {SourceContext}\n" +
"{#if Scope is not null}" +
" {#each s in Scope}=> {s}{#delimit} {#end}\n" +
"{#end}" +
" {@m}\n" +
"{@x}",
theme: melon))
.CreateLogger();
var program = log.ForContext();
program.Information("Host listening at {ListenUri}", "https://hello-world.local");
program
.ForContext("Scope", new[] {"Main", "TextFormattingExample2()"})
.Information("HTTP {Method} {Path} responded {StatusCode} in {Elapsed:0.000} ms", "GET", "/api/hello", 200, 1.23);
program.Warning("We've reached the end of the line");
}
================================================
FILE: example/Sample/Sample.csproj
================================================
net9.0
Exe
false
================================================
FILE: global.json
================================================
{
"sdk": {
"version": "9.0.200",
"allowPrerelease": false,
"rollForward": "latestFeature"
}
}
================================================
FILE: serilog-expressions.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31410.223
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{91E482DE-E1E7-4CE1-9511-C0AF07F3648A}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "global", "global", "{24B1126F-184C-469E-9F06-C1019DEF165A}"
ProjectSection(SolutionItems) = preProject
.gitattributes = .gitattributes
.gitignore = .gitignore
Build.ps1 = Build.ps1
Directory.Build.props = Directory.Build.props
LICENSE = LICENSE
README.md = README.md
RunPerfTests.ps1 = RunPerfTests.ps1
Directory.Version.props = Directory.Version.props
global.json = global.json
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "example", "example", "{BD94A77E-34B1-478E-B921-E87A5F71B574}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{B03B3086-D197-4B32-9AE2-8536C345EA2D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample", "example\Sample\Sample.csproj", "{776EECAC-3C50-45EA-847D-0EBE5158E51E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Serilog.Expressions", "src\Serilog.Expressions\Serilog.Expressions.csproj", "{A420C4E3-3A2D-4369-88EB-77E4DB1D0219}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Serilog.Expressions.Tests", "test\Serilog.Expressions.Tests\Serilog.Expressions.Tests.csproj", "{3C2D8E01-5580-426A-BDD9-EC59CD98E618}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Serilog.Expressions.PerformanceTests", "test\Serilog.Expressions.PerformanceTests\Serilog.Expressions.PerformanceTests.csproj", "{D7A37F73-BBA3-4DAE-9648-1A753A86F968}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{776EECAC-3C50-45EA-847D-0EBE5158E51E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{776EECAC-3C50-45EA-847D-0EBE5158E51E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{776EECAC-3C50-45EA-847D-0EBE5158E51E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{776EECAC-3C50-45EA-847D-0EBE5158E51E}.Release|Any CPU.Build.0 = Release|Any CPU
{A420C4E3-3A2D-4369-88EB-77E4DB1D0219}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A420C4E3-3A2D-4369-88EB-77E4DB1D0219}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A420C4E3-3A2D-4369-88EB-77E4DB1D0219}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A420C4E3-3A2D-4369-88EB-77E4DB1D0219}.Release|Any CPU.Build.0 = Release|Any CPU
{3C2D8E01-5580-426A-BDD9-EC59CD98E618}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3C2D8E01-5580-426A-BDD9-EC59CD98E618}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3C2D8E01-5580-426A-BDD9-EC59CD98E618}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3C2D8E01-5580-426A-BDD9-EC59CD98E618}.Release|Any CPU.Build.0 = Release|Any CPU
{D7A37F73-BBA3-4DAE-9648-1A753A86F968}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D7A37F73-BBA3-4DAE-9648-1A753A86F968}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D7A37F73-BBA3-4DAE-9648-1A753A86F968}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D7A37F73-BBA3-4DAE-9648-1A753A86F968}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{776EECAC-3C50-45EA-847D-0EBE5158E51E} = {BD94A77E-34B1-478E-B921-E87A5F71B574}
{A420C4E3-3A2D-4369-88EB-77E4DB1D0219} = {91E482DE-E1E7-4CE1-9511-C0AF07F3648A}
{3C2D8E01-5580-426A-BDD9-EC59CD98E618} = {B03B3086-D197-4B32-9AE2-8536C345EA2D}
{D7A37F73-BBA3-4DAE-9648-1A753A86F968} = {B03B3086-D197-4B32-9AE2-8536C345EA2D}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {EB6672D6-318E-493E-8B60-77F5A7A90E66}
EndGlobalSection
EndGlobal
================================================
FILE: serilog-expressions.sln.DotSettings
================================================
CI
True
True
True
True
True
True
True
True
True
True
True
True
True
================================================
FILE: src/Serilog.Expressions/Expressions/Ast/AccessorExpression.cs
================================================
// 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.
namespace Serilog.Expressions.Ast;
///
/// An accessor retrieves a property from a (structured) object. For example, in the expression
/// Headers.ContentType the . operator forms an accessor expression that
/// retrieves the ContentType property from the Headers object.
///
/// Note that the AST type can represent accessors that cannot be validly written using
/// . notation. In these cases, if the accessor is formatted back out as an expression,
/// notation will be used.
class AccessorExpression : Expression
{
public AccessorExpression(Expression receiver, string memberName)
{
MemberName = memberName ?? throw new ArgumentNullException(nameof(memberName));
Receiver = receiver;
}
public string MemberName { get; }
public Expression Receiver { get; }
public override string ToString()
{
if (SerilogExpression.IsValidIdentifier(MemberName))
return Receiver + "." + MemberName;
return $"{Receiver}['{SerilogExpression.EscapeStringContent(MemberName)}']";
}
}
================================================
FILE: src/Serilog.Expressions/Expressions/Ast/AmbientNameExpression.cs
================================================
// 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.
namespace Serilog.Expressions.Ast;
///
/// An ambient name is generally a property name or built-in that appears standalone in an expression. For example,
/// in Headers.ContentType, Headers is an ambient name that produces an
/// . Built-ins like @Level are also parsed as ambient names.
///
class AmbientNameExpression : Expression
{
readonly bool _requiresEscape;
public AmbientNameExpression(string name, bool isBuiltIn)
{
PropertyName = name ?? throw new ArgumentNullException(nameof(name));
IsBuiltIn = isBuiltIn;
_requiresEscape = !SerilogExpression.IsValidIdentifier(name);
}
public string PropertyName { get; }
public bool IsBuiltIn { get; }
public override string ToString()
{
if (_requiresEscape)
return $"@Properties['{SerilogExpression.EscapeStringContent(PropertyName)}']";
return (IsBuiltIn ? "@" : "") + PropertyName;
}
}
================================================
FILE: src/Serilog.Expressions/Expressions/Ast/ArrayExpression.cs
================================================
// 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.
namespace Serilog.Expressions.Ast;
///
/// An array expression constructs an array from a list of elements. For example, [1, 2, 3] is an
/// array expression. The items in an array expression can be literal values or expressions, like in the
/// above example, or they can be spread expressions that describe zero or more elements to include in the
/// list. Whether included via regular elements or spread expressions, undefined values are ignored and won't
/// appear in the resulting array value.
///
class ArrayExpression : Expression
{
public ArrayExpression(Element[] elements)
{
Elements = elements ?? throw new ArgumentNullException(nameof(elements));
}
public Element[] Elements { get; }
public override string ToString()
{
return "[" + string.Join(", ", Elements.Select(o => o.ToString())) + "]";
}
}
================================================
FILE: src/Serilog.Expressions/Expressions/Ast/CallExpression.cs
================================================
// 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.
namespace Serilog.Expressions.Ast;
///
/// A is a function call made up of the function name, parenthesised argument
/// list, and optional postfix ci modifier. For example, Substring(RequestPath, 0, 5).
///
class CallExpression : Expression
{
public CallExpression(bool ignoreCase, string operatorName, params Expression[] operands)
{
IgnoreCase = ignoreCase;
OperatorName = operatorName ?? throw new ArgumentNullException(nameof(operatorName));
Operands = operands ?? throw new ArgumentNullException(nameof(operands));
}
public bool IgnoreCase { get; }
public string OperatorName { get; }
public Expression[] Operands { get; }
public override string ToString()
{
return OperatorName
+ "(" + string.Join(", ", Operands.Select(o => o.ToString())) + ")"
+ (IgnoreCase ? " ci" : "");
}
}
================================================
FILE: src/Serilog.Expressions/Expressions/Ast/ConstantExpression.cs
================================================
// 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.Globalization;
using Serilog.Events;
namespace Serilog.Expressions.Ast;
///
/// A constant such as 'hello', true, null, or 123.45.
///
class ConstantExpression : Expression
{
public ConstantExpression(LogEventPropertyValue constant)
{
Constant = constant ?? throw new ArgumentNullException(nameof(constant));
}
public LogEventPropertyValue Constant { get; }
public override string ToString()
{
if (Constant is ScalarValue sv)
{
return sv.Value switch
{
string s => "'" + s.Replace("'", "''") + "'",
true => "true",
false => "false",
IFormattable formattable => formattable.ToString(null, CultureInfo.InvariantCulture),
_ => (sv.Value ?? "null").ToString() ?? ""
};
}
return Constant.ToString();
}
}
================================================
FILE: src/Serilog.Expressions/Expressions/Ast/Element.cs
================================================
// 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.
namespace Serilog.Expressions.Ast;
///
/// An element in an .
///
abstract class Element;
================================================
FILE: src/Serilog.Expressions/Expressions/Ast/Expression.cs
================================================
// 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.
namespace Serilog.Expressions.Ast;
///
/// An AST node.
///
abstract class Expression
{
///
/// The representation of an is not
/// guaranteed to be syntactically valid: this is provided for debugging purposes only.
///
/// A textual representation of the expression.
public abstract override string ToString();
}
================================================
FILE: src/Serilog.Expressions/Expressions/Ast/IndexOfMatchExpression.cs
================================================
// 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.Text.RegularExpressions;
namespace Serilog.Expressions.Ast;
///
/// A non-syntax expression tree node used when compiling the ,
/// , and SQL-style like expressions.
///
class IndexOfMatchExpression : Expression
{
public Expression Corpus { get; }
public Regex Regex { get; }
public IndexOfMatchExpression(Expression corpus, Regex regex)
{
Corpus = corpus ?? throw new ArgumentNullException(nameof(corpus));
Regex = regex ?? throw new ArgumentNullException(nameof(regex));
}
public override string ToString()
{
return $"_Internal_IndexOfMatch({Corpus}, '{Regex.ToString().Replace("'", "''")}')";
}
}
================================================
FILE: src/Serilog.Expressions/Expressions/Ast/IndexerExpression.cs
================================================
// 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.
namespace Serilog.Expressions.Ast;
///
/// An retrieves a property from an object, by name, or an item from an array
/// by zero-based numeric index. For example, Headers['Content-Type'] and Items[2] are
/// parsed as indexer expressions.
///
class IndexerExpression : Expression
{
public Expression Receiver { get; }
public Expression Index { get; }
public IndexerExpression(Expression receiver, Expression index)
{
Receiver = receiver;
Index = index;
}
public override string ToString()
{
return $"{Receiver}[{Index}]";
}
}
================================================
FILE: src/Serilog.Expressions/Expressions/Ast/IndexerWildcard.cs
================================================
// 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.
namespace Serilog.Expressions.Ast;
///
/// Describes the wildcard in a .
///
enum IndexerWildcard { Undefined, Any, All }
================================================
FILE: src/Serilog.Expressions/Expressions/Ast/IndexerWildcardExpression.cs
================================================
// 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.
namespace Serilog.Expressions.Ast;
///
/// An indexer wildcard is a placeholder in a property path expression. For example,
/// in Headers[?] = 'test', the question-mark token is a wildcard that means "any property of
/// the Headers object". The other wildcard indexer is the asterisk, meaning "all".
///
class IndexerWildcardExpression : Expression
{
public IndexerWildcardExpression(IndexerWildcard wildcard)
{
Wildcard = wildcard;
}
public IndexerWildcard Wildcard { get; }
public override string ToString()
{
switch (Wildcard)
{
case IndexerWildcard.Any:
return "?";
case IndexerWildcard.All:
return "*";
default:
throw new NotSupportedException("Unrecognized wildcard " + Wildcard);
}
}
}
================================================
FILE: src/Serilog.Expressions/Expressions/Ast/ItemElement.cs
================================================
// 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.
namespace Serilog.Expressions.Ast;
///
/// A single item in an .
///
class ItemElement : Element
{
public Expression Value { get; }
public ItemElement(Expression value)
{
Value = value;
}
public override string ToString()
{
return Value.ToString();
}
}
================================================
FILE: src/Serilog.Expressions/Expressions/Ast/LambdaExpression.cs
================================================
// 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.
namespace Serilog.Expressions.Ast;
///
/// A non-syntax expression tree node used in the compilation of . Only
/// very limited support for lambda expressions is currently present.
///
class LambdaExpression : Expression
{
public LambdaExpression(ParameterExpression[] parameters, Expression body)
{
Parameters = parameters;
Body = body;
}
public ParameterExpression[] Parameters { get; }
public Expression Body { get; }
public override string ToString()
{
return "|" + string.Join(", ", Parameters.Select(p => p.ToString())) + "| {" + Body + "}";
}
}
================================================
FILE: src/Serilog.Expressions/Expressions/Ast/LocalNameExpression.cs
================================================
// 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.
namespace Serilog.Expressions.Ast;
///
/// Represents the iteration variable in template #each directives.
///
class LocalNameExpression : Expression
{
public LocalNameExpression(string name)
{
Name = name ?? throw new ArgumentNullException(nameof(name));
}
public string Name { get; }
public override string ToString()
{
// No unambiguous syntax for this right now, `$` will do to make these stand out when debugging,
// but the result won't round-trip parse.
return $"${Name}";
}
}
================================================
FILE: src/Serilog.Expressions/Expressions/Ast/Member.cs
================================================
// 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.
namespace Serilog.Expressions.Ast;
///
/// A member in an .
///
abstract class Member;
================================================
FILE: src/Serilog.Expressions/Expressions/Ast/ObjectExpression.cs
================================================
// 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.
namespace Serilog.Expressions.Ast;
///
/// Constructs an object given a list of members. Members can be name: value pairs, or spread
/// expressions that include members from another object. Where names conflict, the rightmost appearance of
/// a name wins. Members that evaluate to an undefined value do not appear in the resulting object.
///
class ObjectExpression : Expression
{
public ObjectExpression(Member[] members)
{
Members = members;
}
public Member[] Members { get; }
public override string ToString()
{
return "{" + string.Join(", ", Members.Select(m => m.ToString())) + "}";
}
}
================================================
FILE: src/Serilog.Expressions/Expressions/Ast/ParameterExpression.cs
================================================
// 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.
namespace Serilog.Expressions.Ast;
///
/// Non-syntax expression type used to represent parameters in bodies.
///
class ParameterExpression : Expression
{
public ParameterExpression(string parameterName)
{
ParameterName = parameterName;
}
public string ParameterName { get; }
public override string ToString()
{
return "$$" + ParameterName;
}
}
================================================
FILE: src/Serilog.Expressions/Expressions/Ast/PropertyMember.cs
================================================
// 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 Serilog.Events;
namespace Serilog.Expressions.Ast;
///
/// An member comprising an optionally-quoted name and a value, for example
/// the object {Username: 'alice'} includes a single with name
/// Username and value 'alice'.
///
class PropertyMember : Member
{
public string Name { get; }
public Expression Value { get; }
public PropertyMember(string name, Expression value)
{
Name = name;
Value = value;
}
public override string ToString()
{
return $"{new ScalarValue(Name)}: {Value}";
}
}
================================================
FILE: src/Serilog.Expressions/Expressions/Ast/SpreadElement.cs
================================================
// 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.
namespace Serilog.Expressions.Ast;
///
/// An element in an that describes zero or more items to include in the array.
/// Spread elements are written with two dots preceding an expression that evaluates to an array of elements to
/// insert into the result array at the position of the spread element, for example, in [1, 2, ..Others],
/// the ..Others expression is a spread element. If the value of the array in the spread is
/// undefined, no items will be added to the list.
///
class SpreadElement : Element
{
public Expression Content { get; }
public SpreadElement(Expression content)
{
Content = content;
}
public override string ToString()
{
return $"..{Content}";
}
}
================================================
FILE: src/Serilog.Expressions/Expressions/Ast/SpreadMember.cs
================================================
// 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.
namespace Serilog.Expressions.Ast;
///
/// An member that designates another object from which to copy members into the
/// current object. Spread member expressions comprise two dots preceding an expression that is expected to
/// evaluate to an object.
///
class SpreadMember : Member
{
public Expression Content { get; }
public SpreadMember(Expression content)
{
Content = content;
}
public override string ToString()
{
return $"..{Content}";
}
}
================================================
FILE: src/Serilog.Expressions/Expressions/BuiltInProperty.cs
================================================
// 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.
namespace Serilog.Expressions;
// See https://github.com/serilog/serilog-formatting-compact#reified-properties
static class BuiltInProperty
{
public const string Exception = "x";
public const string Level = "l";
public const string Timestamp = "t";
public const string Message = "m";
public const string MessageTemplate = "mt";
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";
}
================================================
FILE: src/Serilog.Expressions/Expressions/Compilation/Arrays/ConstantArrayEvaluator.cs
================================================
// 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 Serilog.Events;
using Serilog.Expressions.Ast;
using Serilog.Expressions.Compilation.Transformations;
namespace Serilog.Expressions.Compilation.Arrays;
class ConstantArrayEvaluator : IdentityTransformer
{
static readonly ConstantArrayEvaluator Instance = new();
public static Expression Rewrite(Expression expression)
{
return Instance.Transform(expression);
}
protected override Expression Transform(ArrayExpression ax)
{
// This should probably go depth-first.
if (ax.Elements.All(el => el is ItemElement item &&
item.Value is ConstantExpression))
{
return new ConstantExpression(
new SequenceValue(ax.Elements
.Cast()
.Select(item => ((ConstantExpression)item.Value).Constant)));
}
return base.Transform(ax);
}
}
================================================
FILE: src/Serilog.Expressions/Expressions/Compilation/DefaultFunctionNameResolver.cs
================================================
// 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 Serilog.Expressions.Runtime;
namespace Serilog.Expressions.Compilation;
static class DefaultFunctionNameResolver
{
public static NameResolver Build(NameResolver? additionalNameResolver)
{
var defaultResolver = new StaticMemberNameResolver(typeof(RuntimeOperators));
return additionalNameResolver == null
? defaultResolver
: new OrderedNameResolver(new[] {defaultResolver, additionalNameResolver });
}
}
================================================
FILE: src/Serilog.Expressions/Expressions/Compilation/ExpressionCompiler.cs
================================================
// 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 Serilog.Expressions.Ast;
using Serilog.Expressions.Compilation.Arrays;
using Serilog.Expressions.Compilation.Linq;
using Serilog.Expressions.Compilation.Properties;
using Serilog.Expressions.Compilation.Text;
using Serilog.Expressions.Compilation.Variadics;
using Serilog.Expressions.Compilation.Wildcards;
namespace Serilog.Expressions.Compilation;
static class ExpressionCompiler
{
public static Expression Translate(Expression expression)
{
var actual = expression;
actual = VariadicCallRewriter.Rewrite(actual);
actual = TextMatchingTransformer.Rewrite(actual);
actual = LikeSyntaxTransformer.Rewrite(actual);
actual = PropertiesObjectAccessorTransformer.Rewrite(actual);
actual = ConstantArrayEvaluator.Rewrite(actual);
actual = WildcardComprehensionTransformer.Rewrite(actual);
return actual;
}
public static Evaluatable Compile(Expression expression, IFormatProvider? formatProvider, NameResolver nameResolver)
{
var actual = Translate(expression);
return LinqExpressionCompiler.Compile(actual, formatProvider, nameResolver);
}
}
================================================
FILE: src/Serilog.Expressions/Expressions/Compilation/ExpressionValidationException.cs
================================================
// 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.
namespace Serilog.Expressions.Compilation;
class ExpressionValidationException : ArgumentException
{
public ExpressionValidationException(string message) : base(message)
{
}
public ExpressionValidationException(string message, Exception innerException) : base(message, innerException)
{
}
}
================================================
FILE: src/Serilog.Expressions/Expressions/Compilation/Linq/EventIdHash.cs
================================================
// 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.
// ReSharper disable ForCanBeConvertedToForeach
namespace Serilog.Expressions.Compilation.Linq;
///
/// Hash functions for message templates. See .
///
public static class EventIdHash
{
///
/// Compute a 32-bit hash of the provided . The
/// resulting hash value can be uses as an event id in lieu of transmitting the
/// full template string.
///
/// A message template.
/// A 32-bit hash of the template.
[CLSCompliant(false)]
public static uint Compute(string messageTemplate)
{
if (messageTemplate == null) throw new ArgumentNullException(nameof(messageTemplate));
// Jenkins one-at-a-time https://en.wikipedia.org/wiki/Jenkins_hash_function
unchecked
{
uint hash = 0;
for (var i = 0; i < messageTemplate.Length; ++i)
{
hash += messageTemplate[i];
hash += hash << 10;
hash ^= hash >> 6;
}
hash += hash << 3;
hash ^= hash >> 11;
hash += hash << 15;
return hash;
}
}
}
================================================
FILE: src/Serilog.Expressions/Expressions/Compilation/Linq/ExpressionConstantMapper.cs
================================================
// 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.Linq.Expressions;
using Serilog.Events;
namespace Serilog.Expressions.Compilation.Linq;
class ExpressionConstantMapper : ExpressionVisitor
{
readonly IDictionary