├── .gitattributes
├── .github
└── workflows
│ └── ci.yml
├── .gitignore
├── Build.ps1
├── CHANGES.md
├── Directory.Build.props
├── Directory.Version.props
├── LICENSE
├── README.md
├── assets
├── Serilog.snk
└── icon.png
├── global.json
├── samples
├── SimpleServiceSample
│ ├── PrintTimeService.cs
│ ├── Program.cs
│ ├── Properties
│ │ └── launchSettings.json
│ ├── SimpleServiceSample.csproj
│ ├── appsettings.Development.json
│ └── appsettings.json
└── WebApplicationSample
│ ├── Program.cs
│ ├── Properties
│ └── launchSettings.json
│ ├── WebApplicationSample.csproj
│ ├── appsettings.Development.json
│ └── appsettings.json
├── serilog-extensions-hosting.sln
├── serilog-extensions-hosting.sln.DotSettings
├── src
└── Serilog.Extensions.Hosting
│ ├── Extensions
│ └── Hosting
│ │ ├── AmbientDiagnosticContextCollector.cs
│ │ ├── CachingReloadableLogger.cs
│ │ ├── DiagnosticContext.cs
│ │ ├── DiagnosticContextCollector.cs
│ │ ├── FixedPropertyEnricher.cs
│ │ ├── IReloadableLogger.cs
│ │ ├── InjectedLoggerSettings.cs
│ │ ├── LoggerBase.cs
│ │ ├── NullEnricher.cs
│ │ └── ReloadableLogger.cs
│ ├── IDiagnosticContext.cs
│ ├── LoggerConfigurationExtensions.cs
│ ├── LoggerSettingsConfigurationExtensions.cs
│ ├── Properties
│ └── AssemblyInfo.cs
│ ├── Serilog.Extensions.Hosting.csproj
│ ├── SerilogHostBuilderExtensions.cs
│ └── SerilogServiceCollectionExtensions.cs
└── test
└── Serilog.Extensions.Hosting.Tests
├── DiagnosticContextTests.cs
├── LoggerSettingsConfigurationExtensionsTests.cs
├── ReloadableLoggerTests.cs
├── Serilog.Extensions.Hosting.Tests.csproj
├── SerilogHostBuilderExtensionsTests.cs
├── SerilogServiceCollectionExtensionsTests.cs
└── Support
├── ListSink.cs
└── Some.cs
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 |
3 | * text=auto
4 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | # If this file is renamed, the incrementing run attempt number will be reset.
2 |
3 | name: CI
4 |
5 | on:
6 | push:
7 | branches: [ "dev", "main" ]
8 | pull_request:
9 | branches: [ "dev", "main" ]
10 |
11 | env:
12 | CI_BUILD_NUMBER_BASE: ${{ github.run_number }}
13 | CI_TARGET_BRANCH: ${{ github.head_ref || github.ref_name }}
14 |
15 | jobs:
16 | build:
17 |
18 | # The build must run on Windows so that .NET Framework targets can be built and tested.
19 | runs-on: windows-latest
20 |
21 | permissions:
22 | contents: write
23 |
24 | steps:
25 | - uses: actions/checkout@v4
26 | - name: Setup
27 | uses: actions/setup-dotnet@v4
28 | with:
29 | dotnet-version: 9.0.x
30 | - name: Compute build number
31 | shell: bash
32 | run: |
33 | echo "CI_BUILD_NUMBER=$(($CI_BUILD_NUMBER_BASE+2300))" >> $GITHUB_ENV
34 | - name: Build and Publish
35 | env:
36 | DOTNET_CLI_TELEMETRY_OPTOUT: true
37 | NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
38 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
39 | shell: pwsh
40 | run: |
41 | ./Build.ps1
42 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # MSTest test Results
33 | [Tt]est[Rr]esult*/
34 | [Bb]uild[Ll]og.*
35 |
36 | # NUNIT
37 | *.VisualState.xml
38 | TestResult.xml
39 |
40 | # Build Results of an ATL Project
41 | [Dd]ebugPS/
42 | [Rr]eleasePS/
43 | dlldata.c
44 |
45 | # .NET Core
46 | project.lock.json
47 | project.fragment.lock.json
48 | artifacts/
49 |
50 | *_i.c
51 | *_p.c
52 | *_i.h
53 | *.ilk
54 | *.meta
55 | *.obj
56 | *.pch
57 | *.pdb
58 | *.pgc
59 | *.pgd
60 | *.rsp
61 | *.sbr
62 | *.tlb
63 | *.tli
64 | *.tlh
65 | *.tmp
66 | *.tmp_proj
67 | *.log
68 | *.vspscc
69 | *.vssscc
70 | .builds
71 | *.pidb
72 | *.svclog
73 | *.scc
74 |
75 | # Chutzpah Test files
76 | _Chutzpah*
77 |
78 | # Visual C++ cache files
79 | ipch/
80 | *.aps
81 | *.ncb
82 | *.opendb
83 | *.opensdf
84 | *.sdf
85 | *.cachefile
86 | *.VC.db
87 | *.VC.VC.opendb
88 |
89 | # Visual Studio profiler
90 | *.psess
91 | *.vsp
92 | *.vspx
93 | *.sap
94 |
95 | # TFS 2012 Local Workspace
96 | $tf/
97 |
98 | # Guidance Automation Toolkit
99 | *.gpState
100 |
101 | # ReSharper is a .NET coding add-in
102 | _ReSharper*/
103 | *.[Rr]e[Ss]harper
104 | *.DotSettings.user
105 |
106 | # JustCode is a .NET coding add-in
107 | .JustCode
108 |
109 | # TeamCity is a build add-in
110 | _TeamCity*
111 |
112 | # DotCover is a Code Coverage Tool
113 | *.dotCover
114 |
115 | # Visual Studio code coverage results
116 | *.coverage
117 | *.coveragexml
118 |
119 | # NCrunch
120 | _NCrunch_*
121 | .*crunch*.local.xml
122 | nCrunchTemp_*
123 |
124 | # MightyMoose
125 | *.mm.*
126 | AutoTest.Net/
127 |
128 | # Web workbench (sass)
129 | .sass-cache/
130 |
131 | # Installshield output folder
132 | [Ee]xpress/
133 |
134 | # DocProject is a documentation generator add-in
135 | DocProject/buildhelp/
136 | DocProject/Help/*.HxT
137 | DocProject/Help/*.HxC
138 | DocProject/Help/*.hhc
139 | DocProject/Help/*.hhk
140 | DocProject/Help/*.hhp
141 | DocProject/Help/Html2
142 | DocProject/Help/html
143 |
144 | # Click-Once directory
145 | publish/
146 |
147 | # Publish Web Output
148 | *.[Pp]ublish.xml
149 | *.azurePubxml
150 | # TODO: Comment the next line if you want to checkin your web deploy settings
151 | # but database connection strings (with potential passwords) will be unencrypted
152 | *.pubxml
153 | *.publishproj
154 |
155 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
156 | # checkin your Azure Web App publish settings, but sensitive information contained
157 | # in these scripts will be unencrypted
158 | PublishScripts/
159 |
160 | # NuGet Packages
161 | *.nupkg
162 | # The packages folder can be ignored because of Package Restore
163 | **/packages/*
164 | # except build/, which is used as an MSBuild target.
165 | !**/packages/build/
166 | # Uncomment if necessary however generally it will be regenerated when needed
167 | #!**/packages/repositories.config
168 | # NuGet v3's project.json files produces more ignorable files
169 | *.nuget.props
170 | *.nuget.targets
171 |
172 | # Microsoft Azure Build Output
173 | csx/
174 | *.build.csdef
175 |
176 | # Microsoft Azure Emulator
177 | ecf/
178 | rcf/
179 |
180 | # Windows Store app package directories and files
181 | AppPackages/
182 | BundleArtifacts/
183 | Package.StoreAssociation.xml
184 | _pkginfo.txt
185 |
186 | # Visual Studio cache files
187 | # files ending in .cache can be ignored
188 | *.[Cc]ache
189 | # but keep track of directories ending in .cache
190 | !*.[Cc]ache/
191 |
192 | # Others
193 | ClientBin/
194 | ~$*
195 | *~
196 | *.dbmdl
197 | *.dbproj.schemaview
198 | *.jfm
199 | *.pfx
200 | *.publishsettings
201 | orleans.codegen.cs
202 |
203 | # Since there are multiple workflows, uncomment next line to ignore bower_components
204 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
205 | #bower_components/
206 |
207 | # RIA/Silverlight projects
208 | Generated_Code/
209 |
210 | # Backup & report files from converting an old project file
211 | # to a newer Visual Studio version. Backup files are not needed,
212 | # because we have git ;-)
213 | _UpgradeReport_Files/
214 | Backup*/
215 | UpgradeLog*.XML
216 | UpgradeLog*.htm
217 |
218 | # SQL Server files
219 | *.mdf
220 | *.ldf
221 | *.ndf
222 |
223 | # Business Intelligence projects
224 | *.rdl.data
225 | *.bim.layout
226 | *.bim_*.settings
227 |
228 | # Microsoft Fakes
229 | FakesAssemblies/
230 |
231 | # GhostDoc plugin setting file
232 | *.GhostDoc.xml
233 |
234 | # Node.js Tools for Visual Studio
235 | .ntvs_analysis.dat
236 | node_modules/
237 |
238 | # Typescript v1 declaration files
239 | typings/
240 |
241 | # Visual Studio 6 build log
242 | *.plg
243 |
244 | # Visual Studio 6 workspace options file
245 | *.opt
246 |
247 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
248 | *.vbw
249 |
250 | # Visual Studio LightSwitch build output
251 | **/*.HTMLClient/GeneratedArtifacts
252 | **/*.DesktopClient/GeneratedArtifacts
253 | **/*.DesktopClient/ModelManifest.xml
254 | **/*.Server/GeneratedArtifacts
255 | **/*.Server/ModelManifest.xml
256 | _Pvt_Extensions
257 |
258 | # Paket dependency manager
259 | .paket/paket.exe
260 | paket-files/
261 |
262 | # FAKE - F# Make
263 | .fake/
264 |
265 | # JetBrains Rider
266 | .idea/
267 | *.sln.iml
268 |
269 | # CodeRush
270 | .cr/
271 |
272 | # Python Tools for Visual Studio (PTVS)
273 | __pycache__/
274 | *.pyc
275 |
276 | # Cake - Uncomment if you are using it
277 | # tools/**
278 | # !tools/packages.config
279 |
280 | # Telerik's JustMock configuration file
281 | *.jmconfig
282 |
283 | # BizTalk build output
284 | *.btp.cs
285 | *.btm.cs
286 | *.odx.cs
287 | *.xsd.cs
288 | /samples/WebApplicationSample/logs/
289 |
290 | .DS_Store
291 |
292 |
--------------------------------------------------------------------------------
/Build.ps1:
--------------------------------------------------------------------------------
1 | Write-Output "build: Tool versions follow"
2 |
3 | dotnet --version
4 | dotnet --list-sdks
5 |
6 | Write-Output "build: Build started"
7 |
8 | Push-Location $PSScriptRoot
9 | try {
10 | if(Test-Path .\artifacts) {
11 | Write-Output "build: Cleaning ./artifacts"
12 | Remove-Item ./artifacts -Force -Recurse
13 | }
14 |
15 | & dotnet restore --no-cache
16 |
17 | $dbp = [Xml] (Get-Content .\Directory.Version.props)
18 | $versionPrefix = $dbp.Project.PropertyGroup.VersionPrefix
19 |
20 | Write-Output "build: Package version prefix is $versionPrefix"
21 |
22 | $branch = @{ $true = $env:CI_TARGET_BRANCH; $false = $(git symbolic-ref --short -q HEAD) }[$NULL -ne $env:CI_TARGET_BRANCH];
23 | $revision = @{ $true = "{0:00000}" -f [convert]::ToInt32("0" + $env:CI_BUILD_NUMBER, 10); $false = "local" }[$NULL -ne $env:CI_BUILD_NUMBER];
24 | $suffix = @{ $true = ""; $false = "$($branch.Substring(0, [math]::Min(10,$branch.Length)) -replace '([^a-zA-Z0-9\-]*)', '')-$revision"}[$branch -eq "main" -and $revision -ne "local"]
25 | $commitHash = $(git rev-parse --short HEAD)
26 | $buildSuffix = @{ $true = "$($suffix)-$($commitHash)"; $false = "$($branch)-$($commitHash)" }[$suffix -ne ""]
27 |
28 | Write-Output "build: Package version suffix is $suffix"
29 | Write-Output "build: Build version suffix is $buildSuffix"
30 |
31 | & dotnet build -c Release --version-suffix=$buildSuffix /p:ContinuousIntegrationBuild=true
32 | if($LASTEXITCODE -ne 0) { throw "Build failed" }
33 |
34 | foreach ($src in Get-ChildItem src/*) {
35 | Push-Location $src
36 |
37 | Write-Output "build: Packaging project in $src"
38 |
39 | if ($suffix) {
40 | & dotnet pack -c Release --no-build --no-restore -o ../../artifacts --version-suffix=$suffix
41 | } else {
42 | & dotnet pack -c Release --no-build --no-restore -o ../../artifacts
43 | }
44 | if($LASTEXITCODE -ne 0) { throw "Packaging failed" }
45 |
46 | Pop-Location
47 | }
48 |
49 | foreach ($test in Get-ChildItem test/*.Tests) {
50 | Push-Location $test
51 |
52 | Write-Output "build: Testing project in $test"
53 |
54 | & dotnet test -c Release --no-build --no-restore
55 | if($LASTEXITCODE -ne 0) { throw "Testing failed" }
56 |
57 | Pop-Location
58 | }
59 |
60 | if ($env:NUGET_API_KEY) {
61 | # GitHub Actions will only supply this to branch builds and not PRs. We publish
62 | # builds from any branch this action targets (i.e. main and dev).
63 |
64 | Write-Output "build: Publishing NuGet packages"
65 |
66 | foreach ($nupkg in Get-ChildItem artifacts/*.nupkg) {
67 | & dotnet nuget push -k $env:NUGET_API_KEY -s https://api.nuget.org/v3/index.json "$nupkg"
68 | if($LASTEXITCODE -ne 0) { throw "Publishing failed" }
69 | }
70 |
71 | if (!($suffix)) {
72 | Write-Output "build: Creating release for version $versionPrefix"
73 |
74 | iex "gh release create v$versionPrefix --title v$versionPrefix --generate-notes $(get-item ./artifacts/*.nupkg) $(get-item ./artifacts/*.snupkg)"
75 | }
76 | }
77 | } finally {
78 | Pop-Location
79 | }
80 |
--------------------------------------------------------------------------------
/CHANGES.md:
--------------------------------------------------------------------------------
1 | 2.0.0
2 |
3 | * Initial version for ASP.NET Core 2.1 RC1.
4 |
5 |
--------------------------------------------------------------------------------
/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 | latest
7 | True
8 |
9 | true
10 | $(MSBuildThisFileDirectory)assets/Serilog.snk
11 | false
12 | enable
13 | enable
14 | true
15 | true
16 | true
17 | true
18 | snupkg
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/Directory.Version.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 9.0.1
5 |
6 |
7 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Serilog.Extensions.Hosting [](https://github.com/serilog/serilog-extensions-hosting/actions) [](https://www.nuget.org/packages/Serilog.Extensions.Hosting/)
2 |
3 | Serilog logging for _Microsoft.Extensions.Hosting_. This package routes framework log messages through Serilog, so you can get information about the framework's internal operations written to the same Serilog sinks as your application events.
4 |
5 | **Versioning:** This package tracks the versioning and target framework support of its
6 | [_Microsoft.Extensions.Hosting_](https://nuget.org/packages/Microsoft.Extensions.Hosting) dependency. Most users should choose the version of _Serilog.Extensions.Hosting_ that matches
7 | their application's target framework. I.e. if you're targeting .NET 7.x, choose a 7.x version of _Serilog.Extensions.Hosting_. If
8 | you're targeting .NET 8.x, choose an 8.x _Serilog.Extensions.Hosting_ version, and so on.
9 |
10 | ### Instructions
11 |
12 | **First**, install the _Serilog.Extensions.Hosting_ [NuGet package](https://www.nuget.org/packages/Serilog.Extensions.Hosting) into your app. You will need a way to view the log messages - _Serilog.Sinks.Console_ writes these to the console; there are [many more sinks available](https://www.nuget.org/packages?q=Tags%3A%22serilog%22) on NuGet.
13 |
14 | ```powershell
15 | dotnet add package Serilog.Extensions.Hosting
16 | dotnet add package Serilog.Sinks.Console
17 | ```
18 |
19 | **Next**, in your application's _Program.cs_ file, configure Serilog first. A `try`/`catch` block will ensure any configuration issues are appropriately logged. Call `AddSerilog()` on the host application builder:
20 |
21 | ```csharp
22 | using Serilog;
23 |
24 | Log.Logger = new LoggerConfiguration()
25 | .Enrich.FromLogContext()
26 | .WriteTo.Console()
27 | .CreateLogger();
28 |
29 | try
30 | {
31 | Log.Information("Starting host");
32 |
33 | var builder = Host.CreateApplicationBuilder(args);
34 | builder.Services.AddHostedService();
35 | builder.Services.AddSerilog();
36 |
37 | var app = builder.Build();
38 |
39 | await app.RunAsync();
40 | return 0;
41 | }
42 | catch (Exception ex)
43 | {
44 | Log.Fatal(ex, "Host terminated unexpectedly");
45 | return 1;
46 | }
47 | finally
48 | {
49 | await Log.CloseAndFlushAsync();
50 | }
51 | ```
52 |
53 | **Finally**, clean up by removing the remaining `"Logging"` section from _appsettings.json_ files (this can be replaced with [Serilog configuration](https://github.com/serilog/serilog-settings-configuration) as shown in [this example](https://github.com/serilog/serilog-extensions-hosting/blob/dev/samples/SimpleServiceSample/Program.cs), if required)
54 |
55 | That's it! You will see log output like:
56 |
57 | ```
58 | [22:10:39 INF] Getting the motors running...
59 | [22:10:39 INF] The current time is: 12/05/2018 10:10:39 +00:00
60 | ```
61 |
62 | A more complete example, showing _appsettings.json_ configuration, can be found in [the sample project here](https://github.com/serilog/serilog-extensions-hosting/tree/dev/samples/SimpleServiceSample).
63 |
64 | ### Using the package
65 |
66 | With _Serilog.Extensions.Hosting_ installed and configured, you can write log messages directly through Serilog or any `ILogger` interface injected by .NET. All loggers will use the same underlying implementation, levels, and destinations.
67 |
68 | ### Inline initialization
69 |
70 | You can alternatively configure Serilog using a delegate as shown below:
71 |
72 | ```csharp
73 | // dotnet add package Serilog.Settings.Configuration
74 | builder.Services.AddSerilog((services, loggerConfiguration) => loggerConfiguration
75 | .ReadFrom.Configuration(builder.Configuration)
76 | .Enrich.FromLogContext()
77 | .WriteTo.Console())
78 | ```
79 |
80 | This has the advantage of making `builder`'s `Configuration` object available for configuration of the logger, but at the expense of ignoring `Exception`s raised earlier in program startup.
81 |
82 | If this method is used, `Log.Logger` is assigned implicitly, and closed when the app is shut down.
83 |
--------------------------------------------------------------------------------
/assets/Serilog.snk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serilog/serilog-extensions-hosting/962e7214eb7dd5fb3b2e4347189baf5c9d260d9a/assets/Serilog.snk
--------------------------------------------------------------------------------
/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/serilog/serilog-extensions-hosting/962e7214eb7dd5fb3b2e4347189baf5c9d260d9a/assets/icon.png
--------------------------------------------------------------------------------
/global.json:
--------------------------------------------------------------------------------
1 | {
2 | "sdk": {
3 | "version": "9.0.100",
4 | "allowPrerelease": false,
5 | "rollForward": "latestFeature"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/samples/SimpleServiceSample/PrintTimeService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 | using Microsoft.Extensions.Hosting;
5 | using Microsoft.Extensions.Logging;
6 |
7 | namespace SimpleServiceSample;
8 |
9 | public class PrintTimeService : BackgroundService
10 | {
11 | private readonly ILogger _logger;
12 |
13 | public PrintTimeService(ILogger logger)
14 | {
15 | _logger = logger;
16 | }
17 |
18 | protected override async Task ExecuteAsync(CancellationToken stoppingToken)
19 | {
20 | while (!stoppingToken.IsCancellationRequested)
21 | {
22 | _logger.LogInformation("The current time is: {CurrentTime}", DateTimeOffset.UtcNow);
23 | await Task.Delay(TimeSpan.FromSeconds(5), stoppingToken);
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/samples/SimpleServiceSample/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.Extensions.DependencyInjection;
3 | using Microsoft.Extensions.Hosting;
4 | using Serilog;
5 | using SimpleServiceSample;
6 |
7 | Log.Logger = new LoggerConfiguration()
8 | .Enrich.FromLogContext()
9 | .WriteTo.Console()
10 | .CreateBootstrapLogger();
11 |
12 | try
13 | {
14 | Log.Information("Getting the motors running...");
15 |
16 | var builder = Host.CreateApplicationBuilder(args);
17 |
18 | builder.Services.AddHostedService();
19 |
20 | builder.Services.AddSerilog((services, loggerConfiguration) => loggerConfiguration
21 | .ReadFrom.Configuration(builder.Configuration)
22 | .ReadFrom.Services(services)
23 | .Enrich.FromLogContext()
24 | .WriteTo.Console());
25 |
26 | var app = builder.Build();
27 |
28 | await app.RunAsync();
29 |
30 | return 0;
31 | }
32 | catch (Exception ex)
33 | {
34 | Log.Fatal(ex, "Host terminated unexpectedly");
35 | return 1;
36 | }
37 | finally
38 | {
39 | await Log.CloseAndFlushAsync();
40 | }
41 |
--------------------------------------------------------------------------------
/samples/SimpleServiceSample/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "SimpleServiceSample": {
4 | "commandName": "Project",
5 | "environmentVariables": {
6 | "ASPNETCORE_ENVIRONMENT": "Development"
7 | }
8 | }
9 | }
10 | }
--------------------------------------------------------------------------------
/samples/SimpleServiceSample/SimpleServiceSample.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net9.0
5 | false
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/samples/SimpleServiceSample/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Serilog": {
3 | "MinimumLevel": {
4 | "Default": "Debug"
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/samples/SimpleServiceSample/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Serilog": {
3 | "MinimumLevel": {
4 | "Default": "Debug",
5 | "Override": {
6 | "Microsoft": "Information",
7 | "System": "Warning"
8 | }
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/samples/WebApplicationSample/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.AspNetCore.Builder;
3 | using Microsoft.AspNetCore.Hosting;
4 | using Microsoft.AspNetCore.Http;
5 | using Microsoft.Extensions.Hosting;
6 | using Serilog;
7 |
8 |
9 | Log.Logger = new LoggerConfiguration()
10 | .WriteTo.Console()
11 | .CreateBootstrapLogger();
12 |
13 | Log.Information("Starting up!");
14 |
15 | try
16 | {
17 | var builder = WebApplication.CreateBuilder();
18 |
19 | builder.Services.AddSerilog((services, loggerConfiguration) => loggerConfiguration
20 | .WriteTo.Console()
21 | .ReadFrom.Configuration(builder.Configuration)
22 | .ReadFrom.Services(services));
23 |
24 | var app = builder.Build();
25 |
26 | app.MapGet("/", () =>
27 | {
28 | Log.Information("Saying hello");
29 | return "Hello World!";
30 | });
31 |
32 | await app.RunAsync();
33 |
34 | Log.Information("Stopped cleanly");
35 | return 0;
36 | }
37 | catch (Exception ex)
38 | {
39 | Log.Fatal(ex, "An unhandled exception occured during bootstrapping");
40 | return 1;
41 | }
42 | finally
43 | {
44 | await Log.CloseAndFlushAsync();
45 | }
46 |
--------------------------------------------------------------------------------
/samples/WebApplicationSample/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "iisSettings": {
3 | "windowsAuthentication": false,
4 | "anonymousAuthentication": true,
5 | "iisExpress": {
6 | "applicationUrl": "http://localhost:15670",
7 | "sslPort": 44322
8 | }
9 | },
10 | "profiles": {
11 | "IIS Express": {
12 | "commandName": "IISExpress",
13 | "launchBrowser": true,
14 | "environmentVariables": {
15 | "ASPNETCORE_ENVIRONMENT": "Development"
16 | }
17 | },
18 | "WebApplicationSample": {
19 | "commandName": "Project",
20 | "launchBrowser": true,
21 | "applicationUrl": "https://localhost:5001;http://localhost:5000",
22 | "environmentVariables": {
23 | "ASPNETCORE_ENVIRONMENT": "Development"
24 | }
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/samples/WebApplicationSample/WebApplicationSample.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net9.0
5 | false
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/samples/WebApplicationSample/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | }
3 |
--------------------------------------------------------------------------------
/samples/WebApplicationSample/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Serilog": {
3 | "MinimumLevel": {
4 | "Default": "Information",
5 | "Override": {
6 | "Microsoft.AspNetCore.Hosting": "Information",
7 | "Microsoft.AspNetCore.Mvc": "Warning",
8 | "Microsoft.AspNetCore.Routing": "Warning"
9 | }
10 | },
11 | "WriteTo": [
12 | {
13 | "Name": "File",
14 | "Args": { "path": "./logs/log-.txt", "rollingInterval": "Day" }
15 | }
16 | ]
17 | },
18 | "AllowedHosts": "*"
19 | }
20 |
--------------------------------------------------------------------------------
/serilog-extensions-hosting.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.26730.12
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{A1893BD1-333D-4DFE-A0F0-DDBB2FE526E0}"
7 | EndProject
8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{E30F638E-BBBE-4AD1-93CE-48CC69CFEFE1}"
9 | EndProject
10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{F2407211-6043-439C-8E06-3641634332E7}"
11 | EndProject
12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "assets", "assets", "{9C21B9DF-AEDD-4AA6-BEA4-912DEF3E5B8E}"
13 | ProjectSection(SolutionItems) = preProject
14 | README.md = README.md
15 | assets\Serilog.snk = assets\Serilog.snk
16 | Build.ps1 = Build.ps1
17 | global.json = global.json
18 | Directory.Version.props = Directory.Version.props
19 | Directory.Build.props = Directory.Build.props
20 | EndProjectSection
21 | EndProject
22 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Serilog.Extensions.Hosting", "src\Serilog.Extensions.Hosting\Serilog.Extensions.Hosting.csproj", "{0549D23F-986B-4FB2-BACE-16FD7A7BC9EF}"
23 | EndProject
24 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Serilog.Extensions.Hosting.Tests", "test\Serilog.Extensions.Hosting.Tests\Serilog.Extensions.Hosting.Tests.csproj", "{AD51759B-CD58-473F-9620-0B0E56A123A1}"
25 | EndProject
26 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleServiceSample", "samples\SimpleServiceSample\SimpleServiceSample.csproj", "{E5A82756-4619-4E6B-8B26-6D83E00E99F0}"
27 | EndProject
28 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebApplicationSample", "samples\WebApplicationSample\WebApplicationSample.csproj", "{1ACDCA67-F404-45AB-9348-98E55E03CB8C}"
29 | EndProject
30 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{5C68E1CE-D650-4500-B32C-21EDD0AAA0A7}"
31 | EndProject
32 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{10168223-6AEF-4B08-B6FD-50C6FD3B6E84}"
33 | ProjectSection(SolutionItems) = preProject
34 | .github\workflows\ci.yml = .github\workflows\ci.yml
35 | EndProjectSection
36 | EndProject
37 | Global
38 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
39 | Debug|Any CPU = Debug|Any CPU
40 | Release|Any CPU = Release|Any CPU
41 | EndGlobalSection
42 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
43 | {0549D23F-986B-4FB2-BACE-16FD7A7BC9EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
44 | {0549D23F-986B-4FB2-BACE-16FD7A7BC9EF}.Debug|Any CPU.Build.0 = Debug|Any CPU
45 | {0549D23F-986B-4FB2-BACE-16FD7A7BC9EF}.Release|Any CPU.ActiveCfg = Release|Any CPU
46 | {0549D23F-986B-4FB2-BACE-16FD7A7BC9EF}.Release|Any CPU.Build.0 = Release|Any CPU
47 | {AD51759B-CD58-473F-9620-0B0E56A123A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
48 | {AD51759B-CD58-473F-9620-0B0E56A123A1}.Debug|Any CPU.Build.0 = Debug|Any CPU
49 | {AD51759B-CD58-473F-9620-0B0E56A123A1}.Release|Any CPU.ActiveCfg = Release|Any CPU
50 | {AD51759B-CD58-473F-9620-0B0E56A123A1}.Release|Any CPU.Build.0 = Release|Any CPU
51 | {E5A82756-4619-4E6B-8B26-6D83E00E99F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
52 | {E5A82756-4619-4E6B-8B26-6D83E00E99F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
53 | {E5A82756-4619-4E6B-8B26-6D83E00E99F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
54 | {E5A82756-4619-4E6B-8B26-6D83E00E99F0}.Release|Any CPU.Build.0 = Release|Any CPU
55 | {1ACDCA67-F404-45AB-9348-98E55E03CB8C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
56 | {1ACDCA67-F404-45AB-9348-98E55E03CB8C}.Debug|Any CPU.Build.0 = Debug|Any CPU
57 | {1ACDCA67-F404-45AB-9348-98E55E03CB8C}.Release|Any CPU.ActiveCfg = Release|Any CPU
58 | {1ACDCA67-F404-45AB-9348-98E55E03CB8C}.Release|Any CPU.Build.0 = Release|Any CPU
59 | EndGlobalSection
60 | GlobalSection(SolutionProperties) = preSolution
61 | HideSolutionNode = FALSE
62 | EndGlobalSection
63 | GlobalSection(NestedProjects) = preSolution
64 | {0549D23F-986B-4FB2-BACE-16FD7A7BC9EF} = {A1893BD1-333D-4DFE-A0F0-DDBB2FE526E0}
65 | {AD51759B-CD58-473F-9620-0B0E56A123A1} = {E30F638E-BBBE-4AD1-93CE-48CC69CFEFE1}
66 | {E5A82756-4619-4E6B-8B26-6D83E00E99F0} = {F2407211-6043-439C-8E06-3641634332E7}
67 | {1ACDCA67-F404-45AB-9348-98E55E03CB8C} = {F2407211-6043-439C-8E06-3641634332E7}
68 | {10168223-6AEF-4B08-B6FD-50C6FD3B6E84} = {5C68E1CE-D650-4500-B32C-21EDD0AAA0A7}
69 | EndGlobalSection
70 | GlobalSection(ExtensibilityGlobals) = postSolution
71 | SolutionGuid = {811E61C5-3871-4633-AFAE-B35B619C8A10}
72 | EndGlobalSection
73 | EndGlobal
74 |
--------------------------------------------------------------------------------
/serilog-extensions-hosting.sln.DotSettings:
--------------------------------------------------------------------------------
1 |
2 | True
3 | True
4 | True
5 | True
6 | True
7 | True
--------------------------------------------------------------------------------
/src/Serilog.Extensions.Hosting/Extensions/Hosting/AmbientDiagnosticContextCollector.cs:
--------------------------------------------------------------------------------
1 | // Copyright 2019 Serilog Contributors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | namespace Serilog.Extensions.Hosting;
16 |
17 | class AmbientDiagnosticContextCollector : IDisposable
18 | {
19 | static readonly AsyncLocal AmbientCollector = new();
20 |
21 | // The indirection here ensures that completing collection cleans up the collector in all
22 | // execution contexts. Via @benaadams' addition to `HttpContextAccessor` :-)
23 | DiagnosticContextCollector? _collector;
24 |
25 | public static DiagnosticContextCollector? Current => AmbientCollector.Value?._collector;
26 |
27 | public static DiagnosticContextCollector Begin()
28 | {
29 | var value = new AmbientDiagnosticContextCollector();
30 | value._collector = new DiagnosticContextCollector(value);
31 | AmbientCollector.Value = value;
32 | return value._collector;
33 | }
34 |
35 | public void Dispose()
36 | {
37 | _collector = null;
38 | if (AmbientCollector.Value == this)
39 | AmbientCollector.Value = null;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/Serilog.Extensions.Hosting/Extensions/Hosting/CachingReloadableLogger.cs:
--------------------------------------------------------------------------------
1 | // Copyright 2020 Serilog Contributors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | using System.Diagnostics.CodeAnalysis;
16 | using Serilog.Core;
17 | using Serilog.Events;
18 |
19 | namespace Serilog.Extensions.Hosting;
20 |
21 | class CachingReloadableLogger : LoggerBase, ILogger, IReloadableLogger
22 | {
23 | readonly ReloadableLogger _reloadableLogger;
24 | readonly Func _configure;
25 | readonly IReloadableLogger _parent;
26 |
27 | ILogger _root;
28 | ILogger? _cached;
29 | bool _frozen;
30 |
31 | public CachingReloadableLogger(ReloadableLogger reloadableLogger, ILogger root, IReloadableLogger parent, Func configure)
32 | {
33 | _reloadableLogger = reloadableLogger;
34 | _parent = parent;
35 | _configure = configure;
36 | _root = root;
37 | _cached = null;
38 | _frozen = false;
39 | }
40 |
41 | public ILogger ReloadLogger()
42 | {
43 | return _configure(_parent.ReloadLogger());
44 | }
45 |
46 | public ILogger ForContext(ILogEventEnricher enricher)
47 | {
48 | if (enricher == null!) return this;
49 |
50 | if (_frozen)
51 | return _cached!.ForContext(enricher);
52 |
53 | if (_reloadableLogger.CreateChild(
54 | _root,
55 | this,
56 | _cached,
57 | p => p.ForContext(enricher),
58 | out var child,
59 | out var newRoot,
60 | out var newCached,
61 | out var frozen))
62 | {
63 | Update(newRoot, newCached, frozen);
64 | }
65 |
66 | return child;
67 | }
68 |
69 | public ILogger ForContext(IEnumerable enrichers)
70 | {
71 | if (enrichers == null!) return this;
72 |
73 | if (_frozen)
74 | return _cached!.ForContext(enrichers);
75 |
76 | if (_reloadableLogger.CreateChild(
77 | _root,
78 | this,
79 | _cached,
80 | p => p.ForContext(enrichers),
81 | out var child,
82 | out var newRoot,
83 | out var newCached,
84 | out var frozen))
85 | {
86 | Update(newRoot, newCached, frozen);
87 | }
88 |
89 | return child;
90 | }
91 |
92 | public ILogger ForContext(string propertyName, object? value, bool destructureObjects = false)
93 | {
94 | if (propertyName == null!) return this;
95 |
96 | if (_frozen)
97 | return _cached!.ForContext(propertyName, value, destructureObjects);
98 |
99 | ILogger child;
100 | if (value == null || value is string || value.GetType().IsPrimitive || value.GetType().IsEnum)
101 | {
102 | // Safe to extend the lifetime of `value` by closing over it.
103 | // This ensures `SourceContext` is passed through appropriately and triggers minimum level overrides.
104 | if (_reloadableLogger.CreateChild(
105 | _root,
106 | this,
107 | _cached,
108 | p => p.ForContext(propertyName, value, destructureObjects),
109 | out child,
110 | out var newRoot,
111 | out var newCached,
112 | out var frozen))
113 | {
114 | Update(newRoot, newCached, frozen);
115 | }
116 | }
117 | else
118 | {
119 | // It's not safe to extend the lifetime of `value` or pass it unexpectedly between threads.
120 | // Changes to destructuring configuration won't be picked up by the cached logger.
121 | var eager = ReloadLogger();
122 | if (!eager.BindProperty(propertyName, value, destructureObjects, out var property))
123 | return this;
124 |
125 | var enricher = new FixedPropertyEnricher(property);
126 |
127 | if (_reloadableLogger.CreateChild(
128 | _root,
129 | this,
130 | _cached,
131 | p => p.ForContext(enricher),
132 | out child,
133 | out var newRoot,
134 | out var newCached,
135 | out var frozen))
136 | {
137 | Update(newRoot, newCached, frozen);
138 | }
139 | }
140 |
141 | return child;
142 | }
143 |
144 | public ILogger ForContext()
145 | {
146 | if (_frozen)
147 | return _cached!.ForContext();
148 |
149 | if (_reloadableLogger.CreateChild(
150 | _root,
151 | this,
152 | _cached,
153 | p => p.ForContext(),
154 | out var child,
155 | out var newRoot,
156 | out var newCached,
157 | out var frozen))
158 | {
159 | Update(newRoot, newCached, frozen);
160 | }
161 |
162 | return child;
163 | }
164 |
165 | public ILogger ForContext(Type source)
166 | {
167 | if (_frozen)
168 | return _cached!.ForContext(source);
169 |
170 | if (_reloadableLogger.CreateChild(
171 | _root,
172 | this,
173 | _cached,
174 | p => p.ForContext(source),
175 | out var child,
176 | out var newRoot,
177 | out var newCached,
178 | out var frozen))
179 | {
180 | Update(newRoot, newCached, frozen);
181 | }
182 |
183 | return child;
184 | }
185 |
186 | void Update(ILogger newRoot, ILogger? newCached, bool frozen)
187 | {
188 | _root = newRoot;
189 | _cached = newCached;
190 |
191 | // https://github.com/dotnet/runtime/issues/20500#issuecomment-284774431
192 | // Publish `_cached` and then `_frozen`. This is useful here because it means that once the logger is frozen - which
193 | // we always expect - reads don't require any synchronization/interlocked instructions.
194 | #if FEATURE_MBPW
195 | Interlocked.MemoryBarrierProcessWide();
196 | #else
197 | Thread.MemoryBarrier();
198 | #endif
199 | _frozen = frozen;
200 |
201 | #if FEATURE_MBPW
202 | Interlocked.MemoryBarrierProcessWide();
203 | #else
204 | Thread.MemoryBarrier();
205 | #endif
206 | }
207 |
208 | public override void Write(LogEvent logEvent)
209 | {
210 | if (_frozen)
211 | {
212 | _cached!.Write(logEvent);
213 | return;
214 | }
215 |
216 | if (_reloadableLogger.InvokeWrite(
217 | _root,
218 | _cached,
219 | this,
220 | logEvent,
221 | out var newRoot,
222 | out var newCached,
223 | out var frozen))
224 | {
225 | Update(newRoot, newCached, frozen);
226 | }
227 | }
228 |
229 | public override void Write(LogEventLevel level, string messageTemplate)
230 | {
231 | if (_frozen)
232 | {
233 | _cached!.Write(level, messageTemplate);
234 | return;
235 | }
236 |
237 | if (_reloadableLogger.InvokeWrite(
238 | _root,
239 | _cached,
240 | this,
241 | level,
242 | messageTemplate,
243 | out var newRoot,
244 | out var newCached,
245 | out var frozen))
246 | {
247 | Update(newRoot, newCached, frozen);
248 | }
249 | }
250 |
251 | public override void Write(LogEventLevel level, string messageTemplate, T propertyValue)
252 | {
253 | if (_frozen)
254 | {
255 | _cached!.Write(level, messageTemplate, propertyValue);
256 | return;
257 | }
258 |
259 | if (_reloadableLogger.InvokeWrite(
260 | _root,
261 | _cached,
262 | this,
263 | level,
264 | messageTemplate,
265 | propertyValue,
266 | out var newRoot,
267 | out var newCached,
268 | out var frozen))
269 | {
270 | Update(newRoot, newCached, frozen);
271 | }
272 | }
273 |
274 | public override void Write(LogEventLevel level, string messageTemplate, T0 propertyValue0, T1 propertyValue1)
275 | {
276 | if (_frozen)
277 | {
278 | _cached!.Write(level, messageTemplate, propertyValue0, propertyValue1);
279 | return;
280 | }
281 |
282 | if (_reloadableLogger.InvokeWrite(
283 | _root,
284 | _cached,
285 | this,
286 | level,
287 | messageTemplate,
288 | propertyValue0,
289 | propertyValue1,
290 | out var newRoot,
291 | out var newCached,
292 | out var frozen))
293 | {
294 | Update(newRoot, newCached, frozen);
295 | }
296 | }
297 |
298 | public override void Write(LogEventLevel level, string messageTemplate, T0 propertyValue0, T1 propertyValue1,
299 | T2 propertyValue2)
300 | {
301 | if (_frozen)
302 | {
303 | _cached!.Write(level, messageTemplate, propertyValue0, propertyValue1, propertyValue2);
304 | return;
305 | }
306 |
307 | if (_reloadableLogger.InvokeWrite(
308 | _root,
309 | _cached,
310 | this,
311 | level,
312 | messageTemplate,
313 | propertyValue0,
314 | propertyValue1,
315 | propertyValue2,
316 | out var newRoot,
317 | out var newCached,
318 | out var frozen))
319 | {
320 | Update(newRoot, newCached, frozen);
321 | }
322 | }
323 |
324 | public override void Write(LogEventLevel level, string messageTemplate, params object?[]? propertyValues)
325 | {
326 | if (_frozen)
327 | {
328 | _cached!.Write(level, messageTemplate, propertyValues);
329 | return;
330 | }
331 |
332 | if (_reloadableLogger.InvokeWrite(
333 | _root,
334 | _cached,
335 | this,
336 | level,
337 | messageTemplate,
338 | propertyValues,
339 | out var newRoot,
340 | out var newCached,
341 | out var frozen))
342 | {
343 | Update(newRoot, newCached, frozen);
344 | }
345 | }
346 |
347 | public override void Write(LogEventLevel level, Exception? exception, string messageTemplate)
348 | {
349 | if (_frozen)
350 | {
351 | _cached!.Write(level, exception, messageTemplate);
352 | return;
353 | }
354 |
355 | if (_reloadableLogger.InvokeWrite(
356 | _root,
357 | _cached,
358 | this,
359 | level,
360 | exception,
361 | messageTemplate,
362 | out var newRoot,
363 | out var newCached,
364 | out var frozen))
365 | {
366 | Update(newRoot, newCached, frozen);
367 | }
368 | }
369 |
370 | public override void Write(LogEventLevel level, Exception? exception, string messageTemplate, T propertyValue)
371 | {
372 | if (_frozen)
373 | {
374 | _cached!.Write(level, exception, messageTemplate, propertyValue);
375 | return;
376 | }
377 |
378 | if (_reloadableLogger.InvokeWrite(
379 | _root,
380 | _cached,
381 | this,
382 | level,
383 | exception,
384 | messageTemplate,
385 | propertyValue,
386 | out var newRoot,
387 | out var newCached,
388 | out var frozen))
389 | {
390 | Update(newRoot, newCached, frozen);
391 | }
392 | }
393 |
394 | public override void Write(LogEventLevel level, Exception? exception, string messageTemplate, T0 propertyValue0,
395 | T1 propertyValue1)
396 | {
397 | if (_frozen)
398 | {
399 | _cached!.Write(level, exception, messageTemplate, propertyValue0, propertyValue1);
400 | return;
401 | }
402 |
403 | if (_reloadableLogger.InvokeWrite(
404 | _root,
405 | _cached,
406 | this,
407 | level,
408 | exception,
409 | messageTemplate,
410 | propertyValue0,
411 | propertyValue1,
412 | out var newRoot,
413 | out var newCached,
414 | out var frozen))
415 | {
416 | Update(newRoot, newCached, frozen);
417 | }
418 | }
419 |
420 | public override void Write(LogEventLevel level, Exception? exception, string messageTemplate, T0 propertyValue0,
421 | T1 propertyValue1, T2 propertyValue2)
422 | {
423 | if (_frozen)
424 | {
425 | _cached!.Write(level, exception, messageTemplate, propertyValue0, propertyValue1, propertyValue2);
426 | return;
427 | }
428 |
429 | if (_reloadableLogger.InvokeWrite(
430 | _root,
431 | _cached,
432 | this,
433 | level,
434 | exception,
435 | messageTemplate,
436 | propertyValue0,
437 | propertyValue1,
438 | propertyValue2,
439 | out var newRoot,
440 | out var newCached,
441 | out var frozen))
442 | {
443 | Update(newRoot, newCached, frozen);
444 | }
445 | }
446 |
447 | public override void Write(LogEventLevel level, Exception? exception, string messageTemplate, params object?[]? propertyValues)
448 | {
449 | if (_frozen)
450 | {
451 | _cached!.Write(level, exception, messageTemplate, propertyValues);
452 | return;
453 | }
454 |
455 | if (_reloadableLogger.InvokeWrite(
456 | _root,
457 | _cached,
458 | this,
459 | level,
460 | exception,
461 | messageTemplate,
462 | propertyValues,
463 | out var newRoot,
464 | out var newCached,
465 | out var frozen))
466 | {
467 | Update(newRoot, newCached, frozen);
468 | }
469 | }
470 |
471 | public bool IsEnabled(LogEventLevel level)
472 | {
473 | if (_frozen)
474 | {
475 | return _cached!.IsEnabled(level);
476 | }
477 |
478 | if (_reloadableLogger.InvokeIsEnabled(
479 | _root,
480 | _cached,
481 | this,
482 | level,
483 | out var isEnabled,
484 | out var newRoot,
485 | out var newCached,
486 | out var frozen))
487 | {
488 | Update(newRoot, newCached, frozen);
489 | }
490 |
491 | return isEnabled;
492 | }
493 |
494 | public bool BindMessageTemplate(string messageTemplate, object?[]? propertyValues,
495 | [NotNullWhen(true)]
496 | out MessageTemplate? parsedTemplate,
497 | [NotNullWhen(true)]
498 | out IEnumerable? boundProperties)
499 | {
500 | if (_frozen)
501 | {
502 | return _cached!.BindMessageTemplate(messageTemplate, propertyValues, out parsedTemplate, out boundProperties);
503 | }
504 |
505 | if (_reloadableLogger.InvokeBindMessageTemplate(
506 | _root,
507 | _cached,
508 | this,
509 | messageTemplate,
510 | propertyValues,
511 | out parsedTemplate,
512 | out boundProperties,
513 | out var canBind,
514 | out var newRoot,
515 | out var newCached,
516 | out var frozen))
517 | {
518 | Update(newRoot, newCached, frozen);
519 | }
520 |
521 | return canBind;
522 | }
523 |
524 | public bool BindProperty(string? propertyName, object? value, bool destructureObjects,
525 | [NotNullWhen(true)]
526 | out LogEventProperty? property)
527 | {
528 | if (_frozen)
529 | {
530 | return _cached!.BindProperty(propertyName, value, destructureObjects, out property);
531 | }
532 |
533 | if (_reloadableLogger.InvokeBindProperty(
534 | _root,
535 | _cached,
536 | this,
537 | propertyName,
538 | value,
539 | destructureObjects,
540 | out property,
541 | out var canBind,
542 | out var newRoot,
543 | out var newCached,
544 | out var frozen))
545 | {
546 | Update(newRoot, newCached, frozen);
547 | }
548 |
549 | return canBind;
550 | }
551 | }
552 |
--------------------------------------------------------------------------------
/src/Serilog.Extensions.Hosting/Extensions/Hosting/DiagnosticContext.cs:
--------------------------------------------------------------------------------
1 | // Copyright 2019 Serilog Contributors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | using System;
16 | using System.Threading;
17 |
18 | namespace Serilog.Extensions.Hosting;
19 |
20 | ///
21 | /// Implements an ambient diagnostic context using .
22 | ///
23 | /// Consumers should use to set context properties.
24 | public sealed class DiagnosticContext : IDiagnosticContext
25 | {
26 | readonly ILogger? _logger;
27 |
28 | ///
29 | /// Construct a .
30 | ///
31 | /// A logger for binding properties in the context, or null to use .
32 | public DiagnosticContext(ILogger? logger)
33 | {
34 | _logger = logger;
35 | }
36 |
37 | ///
38 | /// Start collecting properties to associate with the current diagnostic context. This will replace
39 | /// the active collector, if any.
40 | ///
41 | /// A collector that will receive properties added in the current diagnostic context.
42 | public DiagnosticContextCollector BeginCollection()
43 | {
44 | return AmbientDiagnosticContextCollector.Begin();
45 | }
46 |
47 | ///
48 | public void Set(string propertyName, object? value, bool destructureObjects = false)
49 | {
50 | if (propertyName == null) throw new ArgumentNullException(nameof(propertyName));
51 |
52 | var collector = AmbientDiagnosticContextCollector.Current;
53 | if (collector != null &&
54 | (_logger ?? Log.Logger).BindProperty(propertyName, value, destructureObjects, out var property))
55 | {
56 | collector.AddOrUpdate(property);
57 | }
58 | }
59 |
60 | ///
61 | public void SetException(Exception exception)
62 | {
63 | var collector = AmbientDiagnosticContextCollector.Current;
64 | collector?.SetException(exception);
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/Serilog.Extensions.Hosting/Extensions/Hosting/DiagnosticContextCollector.cs:
--------------------------------------------------------------------------------
1 | using Serilog.Events;
2 |
3 | namespace Serilog.Extensions.Hosting;
4 |
5 | ///
6 | /// A container that receives properties added to a diagnostic context.
7 | ///
8 | public sealed class DiagnosticContextCollector : IDisposable
9 | {
10 | readonly IDisposable _chainedDisposable;
11 | readonly object _propertiesLock = new();
12 | Exception? _exception;
13 | Dictionary? _properties = new();
14 |
15 | ///
16 | /// Construct a .
17 | ///
18 | /// An object that will be disposed to signal completion/disposal of
19 | /// the collector.
20 | public DiagnosticContextCollector(IDisposable chainedDisposable)
21 | {
22 | _chainedDisposable = chainedDisposable ?? throw new ArgumentNullException(nameof(chainedDisposable));
23 | }
24 |
25 | ///
26 | /// Add the property to the context.
27 | ///
28 | /// The property to add.
29 | public void AddOrUpdate(LogEventProperty property)
30 | {
31 | if (property == null) throw new ArgumentNullException(nameof(property));
32 |
33 | lock (_propertiesLock)
34 | {
35 | if (_properties == null) return;
36 | _properties[property.Name] = property;
37 | }
38 | }
39 |
40 | ///
41 | /// Set the exception associated with the current diagnostic context.
42 | ///
43 | ///
44 | /// Passing an exception to the diagnostic context is useful when unhandled exceptions are handled before reaching Serilog's
45 | /// RequestLoggingMiddleware. One example is using https://www.nuget.org/packages/Hellang.Middleware.ProblemDetails to transform
46 | /// exceptions to ProblemDetails responses.
47 | ///
48 | ///
49 | /// If an unhandled exception reaches Serilog's RequestLoggingMiddleware, then the unhandled exception takes precedence.
50 | /// If null is given, it clears any previously assigned exception.
51 | ///
52 | /// The exception to log.
53 | public void SetException(Exception exception)
54 | {
55 | lock (_propertiesLock)
56 | {
57 | if (_properties == null) return;
58 | _exception = exception;
59 | }
60 | }
61 |
62 | ///
63 | /// Complete the context and retrieve the properties added to it, if any. This will
64 | /// stop collection and remove the collector from the original execution context and
65 | /// any of its children.
66 | ///
67 | /// The collected properties, or null if no collection is active.
68 | /// True if properties could be collected.
69 | ///
70 | [Obsolete("Replaced by TryComplete(out IEnumerable properties, out Exception exception).")]
71 | public bool TryComplete(out IEnumerable? properties)
72 | {
73 | return TryComplete(out properties, out _);
74 | }
75 |
76 | ///
77 | /// Complete the context and retrieve the properties and exception added to it, if any. This will
78 | /// stop collection and remove the collector from the original execution context and
79 | /// any of its children.
80 | ///
81 | /// The collected properties, or null if no collection is active.
82 | /// The collected exception, or null if none has been collected or if no collection is active.
83 | /// True if properties could be collected.
84 | ///
85 | ///
86 | public bool TryComplete(out IEnumerable? properties, out Exception? exception)
87 | {
88 | lock (_propertiesLock)
89 | {
90 | properties = _properties?.Values;
91 | exception = _exception;
92 | _properties = null;
93 | _exception = null;
94 | Dispose();
95 | return properties != null;
96 | }
97 | }
98 |
99 | ///
100 | public void Dispose()
101 | {
102 | _chainedDisposable.Dispose();
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/src/Serilog.Extensions.Hosting/Extensions/Hosting/FixedPropertyEnricher.cs:
--------------------------------------------------------------------------------
1 | // Copyright 2020 Serilog Contributors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | using Serilog.Core;
16 | using Serilog.Events;
17 |
18 | namespace Serilog.Extensions.Hosting;
19 |
20 | class FixedPropertyEnricher : ILogEventEnricher
21 | {
22 | readonly LogEventProperty _property;
23 |
24 | public FixedPropertyEnricher(LogEventProperty property)
25 | {
26 | _property = property;
27 | }
28 |
29 | public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
30 | {
31 | logEvent.AddPropertyIfAbsent(_property);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/Serilog.Extensions.Hosting/Extensions/Hosting/IReloadableLogger.cs:
--------------------------------------------------------------------------------
1 | // Copyright 2020 Serilog Contributors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | namespace Serilog.Extensions.Hosting;
16 |
17 | interface IReloadableLogger
18 | {
19 | ILogger ReloadLogger();
20 | }
--------------------------------------------------------------------------------
/src/Serilog.Extensions.Hosting/Extensions/Hosting/InjectedLoggerSettings.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.Extensions.DependencyInjection;
3 | using Serilog.Configuration;
4 | using Serilog.Core;
5 |
6 | namespace Serilog.Extensions.Hosting;
7 |
8 | class InjectedLoggerSettings : ILoggerSettings
9 | {
10 | readonly IServiceProvider _services;
11 |
12 | public InjectedLoggerSettings(IServiceProvider services)
13 | {
14 | _services = services ?? throw new ArgumentNullException(nameof(services));
15 | }
16 |
17 | public void Configure(LoggerConfiguration loggerConfiguration)
18 | {
19 | var levelSwitch = _services.GetService();
20 | if (levelSwitch != null)
21 | loggerConfiguration.MinimumLevel.ControlledBy(levelSwitch);
22 |
23 | foreach (var settings in _services.GetServices())
24 | loggerConfiguration.ReadFrom.Settings(settings);
25 |
26 | foreach (var policy in _services.GetServices())
27 | loggerConfiguration.Destructure.With(policy);
28 |
29 | foreach (var enricher in _services.GetServices())
30 | loggerConfiguration.Enrich.With(enricher);
31 |
32 | foreach (var filter in _services.GetServices())
33 | loggerConfiguration.Filter.With(filter);
34 |
35 | foreach (var sink in _services.GetServices())
36 | loggerConfiguration.WriteTo.Sink(sink);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/Serilog.Extensions.Hosting/Extensions/Hosting/LoggerBase.cs:
--------------------------------------------------------------------------------
1 | // Copyright 2020 Serilog Contributors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | using Serilog.Core;
16 | using Serilog.Events;
17 |
18 | namespace Serilog.Extensions.Hosting;
19 |
20 | ///
21 | /// Implements default methods for caching/reloadable loggers.
22 | ///
23 | public abstract class LoggerBase
24 | {
25 | static readonly object[] NoPropertyValues = [];
26 |
27 | internal LoggerBase()
28 | {
29 | }
30 |
31 | ///
32 | /// Write an event to the log.
33 | ///
34 | /// The event to write.
35 | public abstract void Write(LogEvent logEvent);
36 |
37 | ///
38 | /// Write a log event with the specified level.
39 | ///
40 | /// The level of the event.
41 | /// Message template describing the event.
42 | [MessageTemplateFormatMethod("messageTemplate")]
43 | public abstract void Write(LogEventLevel level, string messageTemplate);
44 |
45 | ///
46 | /// Write a log event with the specified level.
47 | ///
48 | /// The level of the event.
49 | /// Message template describing the event.
50 | /// Object positionally formatted into the message template.
51 | [MessageTemplateFormatMethod("messageTemplate")]
52 | public abstract void Write(LogEventLevel level, string messageTemplate, T propertyValue);
53 |
54 | ///
55 | /// Write a log event with the specified level.
56 | ///
57 | /// The level of the event.
58 | /// Message template describing the event.
59 | /// Object positionally formatted into the message template.
60 | /// Object positionally formatted into the message template.
61 | [MessageTemplateFormatMethod("messageTemplate")]
62 | public abstract void Write(LogEventLevel level, string messageTemplate, T0 propertyValue0, T1 propertyValue1);
63 |
64 | ///
65 | /// Write a log event with the specified level.
66 | ///
67 | /// The level of the event.
68 | /// Message template describing the event.
69 | /// Object positionally formatted into the message template.
70 | /// Object positionally formatted into the message template.
71 | /// Object positionally formatted into the message template.
72 | [MessageTemplateFormatMethod("messageTemplate")]
73 | public abstract void Write(LogEventLevel level, string messageTemplate, T0 propertyValue0, T1 propertyValue1,
74 | T2 propertyValue2);
75 |
76 | ///
77 | /// Write a log event with the specified level.
78 | ///
79 | /// The level of the event.
80 | ///
81 | ///
82 | [MessageTemplateFormatMethod("messageTemplate")]
83 | public abstract void Write(LogEventLevel level, string messageTemplate, params object?[]? propertyValues);
84 |
85 | ///
86 | /// Write a log event with the specified level and associated exception.
87 | ///
88 | /// The level of the event.
89 | /// Exception related to the event.
90 | /// Message template describing the event.
91 | [MessageTemplateFormatMethod("messageTemplate")]
92 | public abstract void Write(LogEventLevel level, Exception? exception, string messageTemplate);
93 |
94 | ///
95 | /// Write a log event with the specified level and associated exception.
96 | ///
97 | /// The level of the event.
98 | /// Exception related to the event.
99 | /// Message template describing the event.
100 | /// Object positionally formatted into the message template.
101 | [MessageTemplateFormatMethod("messageTemplate")]
102 | public abstract void Write(LogEventLevel level, Exception? exception, string messageTemplate, T propertyValue);
103 |
104 | ///
105 | /// Write a log event with the specified level and associated exception.
106 | ///
107 | /// The level of the event.
108 | /// Exception related to the event.
109 | /// Message template describing the event.
110 | /// Object positionally formatted into the message template.
111 | /// Object positionally formatted into the message template.
112 | [MessageTemplateFormatMethod("messageTemplate")]
113 | public abstract void Write(LogEventLevel level, Exception? exception, string messageTemplate, T0 propertyValue0,
114 | T1 propertyValue1);
115 |
116 | ///
117 | /// Write a log event with the specified level and associated exception.
118 | ///
119 | /// The level of the event.
120 | /// Exception related to the event.
121 | /// Message template describing the event.
122 | /// Object positionally formatted into the message template.
123 | /// Object positionally formatted into the message template.
124 | /// Object positionally formatted into the message template.
125 | [MessageTemplateFormatMethod("messageTemplate")]
126 | public abstract void Write(LogEventLevel level, Exception? exception, string messageTemplate,
127 | T0 propertyValue0, T1 propertyValue1, T2 propertyValue2);
128 |
129 | ///
130 | /// Write a log event with the specified level and associated exception.
131 | ///
132 | /// The level of the event.
133 | /// Exception related to the event.
134 | /// Message template describing the event.
135 | /// Objects positionally formatted into the message template.
136 | [MessageTemplateFormatMethod("messageTemplate")]
137 | public abstract void Write(LogEventLevel level, Exception? exception, string messageTemplate, params object?[]? propertyValues);
138 |
139 | ///
140 | /// Write a log event with the level.
141 | ///
142 | /// Message template describing the event.
143 | ///
144 | /// Log.Verbose("Staring into space, wondering if we're alone.");
145 | ///
146 | [MessageTemplateFormatMethod("messageTemplate")]
147 | public void Verbose(string messageTemplate)
148 | => Write(LogEventLevel.Verbose, messageTemplate, NoPropertyValues);
149 |
150 | ///
151 | /// Write a log event with the level.
152 | ///
153 | /// Message template describing the event.
154 | /// Object positionally formatted into the message template.
155 | ///
156 | /// Log.Verbose("Staring into space, wondering if we're alone.");
157 | ///
158 | [MessageTemplateFormatMethod("messageTemplate")]
159 | public void Verbose(string messageTemplate, T propertyValue)
160 | => Write(LogEventLevel.Verbose, messageTemplate, propertyValue);
161 |
162 | ///
163 | /// Write a log event with the level.
164 | ///
165 | /// Message template describing the event.
166 | /// Object positionally formatted into the message template.
167 | /// Object positionally formatted into the message template.
168 | ///
169 | /// Log.Verbose("Staring into space, wondering if we're alone.");
170 | ///
171 | [MessageTemplateFormatMethod("messageTemplate")]
172 | public void Verbose(string messageTemplate, T0 propertyValue0, T1 propertyValue1)
173 | => Write(LogEventLevel.Verbose, messageTemplate, propertyValue0, propertyValue1);
174 |
175 | ///
176 | /// Write a log event with the level.
177 | ///
178 | /// Message template describing the event.
179 | /// Object positionally formatted into the message template.
180 | /// Object positionally formatted into the message template.
181 | /// Object positionally formatted into the message template.
182 | ///
183 | /// Log.Verbose("Staring into space, wondering if we're alone.");
184 | ///
185 | [MessageTemplateFormatMethod("messageTemplate")]
186 | public void Verbose(string messageTemplate, T0 propertyValue0, T1 propertyValue1, T2 propertyValue2)
187 | => Write(LogEventLevel.Verbose, messageTemplate, propertyValue0, propertyValue1, propertyValue2);
188 |
189 | ///
190 | /// Write a log event with the level and associated exception.
191 | ///
192 | /// Message template describing the event.
193 | /// Objects positionally formatted into the message template.
194 | ///
195 | /// Log.Verbose("Staring into space, wondering if we're alone.");
196 | ///
197 | [MessageTemplateFormatMethod("messageTemplate")]
198 | public void Verbose(string messageTemplate, params object?[]? propertyValues)
199 | => Verbose((Exception?)null, messageTemplate, propertyValues);
200 |
201 | ///
202 | /// Write a log event with the level and associated exception.
203 | ///
204 | /// Exception related to the event.
205 | /// Message template describing the event.
206 | ///
207 | /// Log.Verbose(ex, "Staring into space, wondering where this comet came from.");
208 | ///
209 | [MessageTemplateFormatMethod("messageTemplate")]
210 | public void Verbose(Exception? exception, string messageTemplate)
211 | => Write(LogEventLevel.Verbose, exception, messageTemplate, NoPropertyValues);
212 |
213 | ///
214 | /// Write a log event with the level and associated exception.
215 | ///
216 | /// Exception related to the event.
217 | /// Message template describing the event.
218 | /// Object positionally formatted into the message template.
219 | ///
220 | /// Log.Verbose(ex, "Staring into space, wondering where this comet came from.");
221 | ///
222 | [MessageTemplateFormatMethod("messageTemplate")]
223 | public void Verbose(Exception? exception, string messageTemplate, T propertyValue)
224 | => Write(LogEventLevel.Verbose, exception, messageTemplate, propertyValue);
225 |
226 | ///
227 | /// Write a log event with the level and associated exception.
228 | ///
229 | /// Exception related to the event.
230 | /// Message template describing the event.
231 | /// Object positionally formatted into the message template.
232 | /// Object positionally formatted into the message template.
233 | ///
234 | /// Log.Verbose(ex, "Staring into space, wondering where this comet came from.");
235 | ///
236 | [MessageTemplateFormatMethod("messageTemplate")]
237 | public void Verbose(Exception? exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1)
238 | => Write(LogEventLevel.Verbose, exception, messageTemplate, propertyValue0, propertyValue1);
239 |
240 | ///
241 | /// Write a log event with the level and associated exception.
242 | ///
243 | /// Exception related to the event.
244 | /// Message template describing the event.
245 | /// Object positionally formatted into the message template.
246 | /// Object positionally formatted into the message template.
247 | /// Object positionally formatted into the message template.
248 | ///
249 | /// Log.Verbose(ex, "Staring into space, wondering where this comet came from.");
250 | ///
251 | [MessageTemplateFormatMethod("messageTemplate")]
252 | public void Verbose(Exception? exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1,
253 | T2 propertyValue2)
254 | => Write(LogEventLevel.Verbose, exception, messageTemplate, propertyValue0, propertyValue1, propertyValue2);
255 |
256 | ///
257 | /// Write a log event with the level and associated exception.
258 | ///
259 | /// Exception related to the event.
260 | /// Message template describing the event.
261 | /// Objects positionally formatted into the message template.
262 | ///
263 | /// Log.Verbose(ex, "Staring into space, wondering where this comet came from.");
264 | ///
265 | [MessageTemplateFormatMethod("messageTemplate")]
266 | public void Verbose(Exception? exception, string messageTemplate, params object?[]? propertyValues)
267 | => Write(LogEventLevel.Verbose, exception, messageTemplate, propertyValues);
268 |
269 | ///
270 | /// Write a log event with the level.
271 | ///
272 | /// Message template describing the event.
273 | ///
274 | /// Log.Debug("Starting up at {StartedAt}.", DateTime.Now);
275 | ///
276 | [MessageTemplateFormatMethod("messageTemplate")]
277 | public void Debug(string messageTemplate)
278 | => Write(LogEventLevel.Debug, messageTemplate, NoPropertyValues);
279 |
280 | ///
281 | /// Write a log event with the level.
282 | ///
283 | /// Message template describing the event.
284 | /// Object positionally formatted into the message template.
285 | ///
286 | /// Log.Debug("Starting up at {StartedAt}.", DateTime.Now);
287 | ///
288 | [MessageTemplateFormatMethod("messageTemplate")]
289 | public void Debug(string messageTemplate, T propertyValue)
290 | => Write(LogEventLevel.Debug, messageTemplate, propertyValue);
291 |
292 | ///
293 | /// Write a log event with the level.
294 | ///
295 | /// Message template describing the event.
296 | /// Object positionally formatted into the message template.
297 | /// Object positionally formatted into the message template.
298 | ///
299 | /// Log.Debug("Starting up at {StartedAt}.", DateTime.Now);
300 | ///
301 | [MessageTemplateFormatMethod("messageTemplate")]
302 | public void Debug(string messageTemplate, T0 propertyValue0, T1 propertyValue1)
303 | => Write(LogEventLevel.Debug, messageTemplate, propertyValue0, propertyValue1);
304 |
305 | ///
306 | /// Write a log event with the level.
307 | ///
308 | /// Message template describing the event.
309 | /// Object positionally formatted into the message template.
310 | /// Object positionally formatted into the message template.
311 | /// Object positionally formatted into the message template.
312 | ///
313 | /// Log.Debug("Starting up at {StartedAt}.", DateTime.Now);
314 | ///
315 | [MessageTemplateFormatMethod("messageTemplate")]
316 | public void Debug(string messageTemplate, T0 propertyValue0, T1 propertyValue1, T2 propertyValue2)
317 | => Write(LogEventLevel.Debug, messageTemplate, propertyValue0, propertyValue1, propertyValue2);
318 |
319 | ///
320 | /// Write a log event with the level and associated exception.
321 | ///
322 | /// Message template describing the event.
323 | /// Objects positionally formatted into the message template.
324 | ///
325 | /// Log.Debug("Starting up at {StartedAt}.", DateTime.Now);
326 | ///
327 | [MessageTemplateFormatMethod("messageTemplate")]
328 | public void Debug(string messageTemplate, params object?[]? propertyValues)
329 | => Debug((Exception?)null, messageTemplate, propertyValues);
330 |
331 | ///
332 | /// Write a log event with the level and associated exception.
333 | ///
334 | /// Exception related to the event.
335 | /// Message template describing the event.
336 | ///
337 | /// Log.Debug(ex, "Swallowing a mundane exception.");
338 | ///
339 | [MessageTemplateFormatMethod("messageTemplate")]
340 | public void Debug(Exception? exception, string messageTemplate)
341 | => Write(LogEventLevel.Debug, exception, messageTemplate, NoPropertyValues);
342 |
343 | ///
344 | /// Write a log event with the level and associated exception.
345 | ///
346 | /// Exception related to the event.
347 | /// Message template describing the event.
348 | /// Object positionally formatted into the message template.
349 | ///
350 | /// Log.Debug(ex, "Swallowing a mundane exception.");
351 | ///
352 | [MessageTemplateFormatMethod("messageTemplate")]
353 | public void Debug(Exception? exception, string messageTemplate, T propertyValue)
354 | => Write(LogEventLevel.Debug, exception, messageTemplate, propertyValue);
355 |
356 | ///
357 | /// Write a log event with the level and associated exception.
358 | ///
359 | /// Exception related to the event.
360 | /// Message template describing the event.
361 | /// Object positionally formatted into the message template.
362 | /// Object positionally formatted into the message template.
363 | ///
364 | /// Log.Debug(ex, "Swallowing a mundane exception.");
365 | ///
366 | [MessageTemplateFormatMethod("messageTemplate")]
367 | public void Debug(Exception? exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1)
368 | => Write(LogEventLevel.Debug, exception, messageTemplate, propertyValue0, propertyValue1);
369 |
370 | ///
371 | /// Write a log event with the level and associated exception.
372 | ///
373 | /// Exception related to the event.
374 | /// Message template describing the event.
375 | /// Object positionally formatted into the message template.
376 | /// Object positionally formatted into the message template.
377 | /// Object positionally formatted into the message template.
378 | ///
379 | /// Log.Debug(ex, "Swallowing a mundane exception.");
380 | ///
381 | [MessageTemplateFormatMethod("messageTemplate")]
382 | public void Debug(Exception? exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1,
383 | T2 propertyValue2)
384 | => Write(LogEventLevel.Debug, exception, messageTemplate, propertyValue0, propertyValue1, propertyValue2);
385 |
386 | ///
387 | /// Write a log event with the level and associated exception.
388 | ///
389 | /// Exception related to the event.
390 | /// Message template describing the event.
391 | /// Objects positionally formatted into the message template.
392 | ///
393 | /// Log.Debug(ex, "Swallowing a mundane exception.");
394 | ///
395 | [MessageTemplateFormatMethod("messageTemplate")]
396 | public void Debug(Exception? exception, string messageTemplate, params object?[]? propertyValues)
397 | => Write(LogEventLevel.Debug, exception, messageTemplate, propertyValues);
398 |
399 | ///
400 | /// Write a log event with the level.
401 | ///
402 | /// Message template describing the event.
403 | ///
404 | /// Log.Information("Processed {RecordCount} records in {TimeMS}.", records.Length, sw.ElapsedMilliseconds);
405 | ///
406 | [MessageTemplateFormatMethod("messageTemplate")]
407 | public void Information(string messageTemplate)
408 | => Write(LogEventLevel.Information, messageTemplate, NoPropertyValues);
409 |
410 | ///
411 | /// Write a log event with the level.
412 | ///
413 | /// Message template describing the event.
414 | /// Object positionally formatted into the message template.
415 | ///
416 | /// Log.Information("Processed {RecordCount} records in {TimeMS}.", records.Length, sw.ElapsedMilliseconds);
417 | ///
418 | [MessageTemplateFormatMethod("messageTemplate")]
419 | public void Information(string messageTemplate, T propertyValue)
420 | => Write(LogEventLevel.Information, messageTemplate, propertyValue);
421 |
422 | ///
423 | /// Write a log event with the level.
424 | ///
425 | /// Message template describing the event.
426 | /// Object positionally formatted into the message template.
427 | /// Object positionally formatted into the message template.
428 | ///
429 | /// Log.Information("Processed {RecordCount} records in {TimeMS}.", records.Length, sw.ElapsedMilliseconds);
430 | ///
431 | [MessageTemplateFormatMethod("messageTemplate")]
432 | public void Information(string messageTemplate, T0 propertyValue0, T1 propertyValue1)
433 | => Write(LogEventLevel.Information, messageTemplate, propertyValue0, propertyValue1);
434 |
435 | ///
436 | /// Write a log event with the level.
437 | ///
438 | /// Message template describing the event.
439 | /// Object positionally formatted into the message template.
440 | /// Object positionally formatted into the message template.
441 | /// Object positionally formatted into the message template.
442 | ///
443 | /// Log.Information("Processed {RecordCount} records in {TimeMS}.", records.Length, sw.ElapsedMilliseconds);
444 | ///
445 | [MessageTemplateFormatMethod("messageTemplate")]
446 | public void Information(string messageTemplate, T0 propertyValue0, T1 propertyValue1, T2 propertyValue2)
447 | => Write(LogEventLevel.Information, messageTemplate, propertyValue0, propertyValue1, propertyValue2);
448 |
449 | ///
450 | /// Write a log event with the level and associated exception.
451 | ///
452 | /// Message template describing the event.
453 | /// Objects positionally formatted into the message template.
454 | ///
455 | /// Log.Information("Processed {RecordCount} records in {TimeMS}.", records.Length, sw.ElapsedMilliseconds);
456 | ///
457 | [MessageTemplateFormatMethod("messageTemplate")]
458 | public void Information(string messageTemplate, params object?[]? propertyValues)
459 | => Information((Exception?)null, messageTemplate, propertyValues);
460 |
461 | ///
462 | /// Write a log event with the level and associated exception.
463 | ///
464 | /// Exception related to the event.
465 | /// Message template describing the event.
466 | ///
467 | /// Log.Information(ex, "Processed {RecordCount} records in {TimeMS}.", records.Length, sw.ElapsedMilliseconds);
468 | ///
469 | [MessageTemplateFormatMethod("messageTemplate")]
470 | public void Information(Exception? exception, string messageTemplate)
471 | => Write(LogEventLevel.Information, exception, messageTemplate, NoPropertyValues);
472 |
473 | ///
474 | /// Write a log event with the level and associated exception.
475 | ///
476 | /// Exception related to the event.
477 | /// Message template describing the event.
478 | /// Object positionally formatted into the message template.
479 | ///
480 | /// Log.Information(ex, "Processed {RecordCount} records in {TimeMS}.", records.Length, sw.ElapsedMilliseconds);
481 | ///
482 | [MessageTemplateFormatMethod("messageTemplate")]
483 | public void Information(Exception? exception, string messageTemplate, T propertyValue)
484 | => Write(LogEventLevel.Information, exception, messageTemplate, propertyValue);
485 |
486 | ///
487 | /// Write a log event with the level and associated exception.
488 | ///
489 | /// Exception related to the event.
490 | /// Message template describing the event.
491 | /// Object positionally formatted into the message template.
492 | /// Object positionally formatted into the message template.
493 | ///
494 | /// Log.Information(ex, "Processed {RecordCount} records in {TimeMS}.", records.Length, sw.ElapsedMilliseconds);
495 | ///
496 | [MessageTemplateFormatMethod("messageTemplate")]
497 | public void Information(Exception? exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1)
498 | => Write(LogEventLevel.Information, exception, messageTemplate, propertyValue0, propertyValue1);
499 |
500 | ///
501 | /// Write a log event with the level and associated exception.
502 | ///
503 | /// Exception related to the event.
504 | /// Message template describing the event.
505 | /// Object positionally formatted into the message template.
506 | /// Object positionally formatted into the message template.
507 | /// Object positionally formatted into the message template.
508 | ///
509 | /// Log.Information(ex, "Processed {RecordCount} records in {TimeMS}.", records.Length, sw.ElapsedMilliseconds);
510 | ///
511 | [MessageTemplateFormatMethod("messageTemplate")]
512 | public void Information(Exception? exception, string messageTemplate, T0 propertyValue0,
513 | T1 propertyValue1, T2 propertyValue2)
514 | => Write(LogEventLevel.Information, exception, messageTemplate, propertyValue0, propertyValue1, propertyValue2);
515 |
516 | ///
517 | /// Write a log event with the level and associated exception.
518 | ///
519 | /// Exception related to the event.
520 | /// Message template describing the event.
521 | /// Objects positionally formatted into the message template.
522 | ///
523 | /// Log.Information(ex, "Processed {RecordCount} records in {TimeMS}.", records.Length, sw.ElapsedMilliseconds);
524 | ///
525 | [MessageTemplateFormatMethod("messageTemplate")]
526 | public void Information(Exception? exception, string messageTemplate, params object?[]? propertyValues)
527 | => Write(LogEventLevel.Information, exception, messageTemplate, propertyValues);
528 |
529 | ///
530 | /// Write a log event with the level.
531 | ///
532 | /// Message template describing the event.
533 | ///
534 | /// Log.Warning("Skipped {SkipCount} records.", skippedRecords.Length);
535 | ///
536 | [MessageTemplateFormatMethod("messageTemplate")]
537 | public void Warning(string messageTemplate)
538 | => Write(LogEventLevel.Warning, messageTemplate, NoPropertyValues);
539 |
540 | ///
541 | /// Write a log event with the level.
542 | ///
543 | /// Message template describing the event.
544 | /// Object positionally formatted into the message template.
545 | ///
546 | /// Log.Warning("Skipped {SkipCount} records.", skippedRecords.Length);
547 | ///
548 | [MessageTemplateFormatMethod("messageTemplate")]
549 | public void Warning(string messageTemplate, T propertyValue)
550 | => Write(LogEventLevel.Warning, messageTemplate, propertyValue);
551 |
552 | ///
553 | /// Write a log event with the level.
554 | ///
555 | /// Message template describing the event.
556 | /// Object positionally formatted into the message template.
557 | /// Object positionally formatted into the message template.
558 | ///
559 | /// Log.Warning("Skipped {SkipCount} records.", skippedRecords.Length);
560 | ///
561 | [MessageTemplateFormatMethod("messageTemplate")]
562 | public void Warning(string messageTemplate, T0 propertyValue0, T1 propertyValue1)
563 | => Write(LogEventLevel.Warning, messageTemplate, propertyValue0, propertyValue1);
564 |
565 | ///
566 | /// Write a log event with the level.
567 | ///
568 | /// Message template describing the event.
569 | /// Object positionally formatted into the message template.
570 | /// Object positionally formatted into the message template.
571 | /// Object positionally formatted into the message template.
572 | ///
573 | /// Log.Warning("Skipped {SkipCount} records.", skippedRecords.Length);
574 | ///
575 | [MessageTemplateFormatMethod("messageTemplate")]
576 | public void Warning(string messageTemplate, T0 propertyValue0, T1 propertyValue1, T2 propertyValue2)
577 | => Write(LogEventLevel.Warning, messageTemplate, propertyValue0, propertyValue1, propertyValue2);
578 |
579 | ///
580 | /// Write a log event with the level and associated exception.
581 | ///
582 | /// Message template describing the event.
583 | /// Objects positionally formatted into the message template.
584 | ///
585 | /// Log.Warning("Skipped {SkipCount} records.", skippedRecords.Length);
586 | ///
587 | [MessageTemplateFormatMethod("messageTemplate")]
588 | public void Warning(string messageTemplate, params object?[]? propertyValues)
589 | => Warning((Exception?)null, messageTemplate, propertyValues);
590 |
591 | ///
592 | /// Write a log event with the level and associated exception.
593 | ///
594 | /// Exception related to the event.
595 | /// Message template describing the event.
596 | ///
597 | /// Log.Warning(ex, "Skipped {SkipCount} records.", skippedRecords.Length);
598 | ///
599 | [MessageTemplateFormatMethod("messageTemplate")]
600 | public void Warning(Exception? exception, string messageTemplate)
601 | => Write(LogEventLevel.Warning, exception, messageTemplate, NoPropertyValues);
602 |
603 | ///
604 | /// Write a log event with the level and associated exception.
605 | ///
606 | /// Exception related to the event.
607 | /// Message template describing the event.
608 | /// Object positionally formatted into the message template.
609 | ///
610 | /// Log.Warning(ex, "Skipped {SkipCount} records.", skippedRecords.Length);
611 | ///
612 | [MessageTemplateFormatMethod("messageTemplate")]
613 | public void Warning(Exception? exception, string messageTemplate, T propertyValue)
614 | => Write(LogEventLevel.Warning, exception, messageTemplate, propertyValue);
615 |
616 | ///
617 | /// Write a log event with the level and associated exception.
618 | ///
619 | /// Exception related to the event.
620 | /// Message template describing the event.
621 | /// Object positionally formatted into the message template.
622 | /// Object positionally formatted into the message template.
623 | ///
624 | /// Log.Warning(ex, "Skipped {SkipCount} records.", skippedRecords.Length);
625 | ///
626 | [MessageTemplateFormatMethod("messageTemplate")]
627 | public void Warning(Exception? exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1)
628 | => Write(LogEventLevel.Warning, exception, messageTemplate, propertyValue0, propertyValue1);
629 |
630 | ///
631 | /// Write a log event with the level and associated exception.
632 | ///
633 | /// Exception related to the event.
634 | /// Message template describing the event.
635 | /// Object positionally formatted into the message template.
636 | /// Object positionally formatted into the message template.
637 | /// Object positionally formatted into the message template.
638 | ///
639 | /// Log.Warning(ex, "Skipped {SkipCount} records.", skippedRecords.Length);
640 | ///
641 | [MessageTemplateFormatMethod("messageTemplate")]
642 | public void Warning(Exception? exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1,
643 | T2 propertyValue2)
644 | => Write(LogEventLevel.Warning, exception, messageTemplate, propertyValue0, propertyValue1, propertyValue2);
645 |
646 | ///
647 | /// Write a log event with the level and associated exception.
648 | ///
649 | /// Exception related to the event.
650 | /// Message template describing the event.
651 | /// Objects positionally formatted into the message template.
652 | ///
653 | /// Log.Warning(ex, "Skipped {SkipCount} records.", skippedRecords.Length);
654 | ///
655 | [MessageTemplateFormatMethod("messageTemplate")]
656 | public void Warning(Exception? exception, string messageTemplate, params object?[]? propertyValues)
657 | => Write(LogEventLevel.Warning, exception, messageTemplate, propertyValues);
658 |
659 | ///
660 | /// Write a log event with the level.
661 | ///
662 | /// Message template describing the event.
663 | ///
664 | /// Log.Error("Failed {ErrorCount} records.", brokenRecords.Length);
665 | ///
666 | [MessageTemplateFormatMethod("messageTemplate")]
667 | public void Error(string messageTemplate)
668 | => Write(LogEventLevel.Error, messageTemplate, NoPropertyValues);
669 |
670 | ///
671 | /// Write a log event with the level.
672 | ///
673 | /// Message template describing the event.
674 | /// Object positionally formatted into the message template.
675 | ///
676 | /// Log.Error("Failed {ErrorCount} records.", brokenRecords.Length);
677 | ///
678 | [MessageTemplateFormatMethod("messageTemplate")]
679 | public void Error(string messageTemplate, T propertyValue)
680 | => Write(LogEventLevel.Error, messageTemplate, propertyValue);
681 |
682 | ///
683 | /// Write a log event with the level.
684 | ///
685 | /// Message template describing the event.
686 | /// Object positionally formatted into the message template.
687 | /// Object positionally formatted into the message template.
688 | ///
689 | /// Log.Error("Failed {ErrorCount} records.", brokenRecords.Length);
690 | ///
691 | [MessageTemplateFormatMethod("messageTemplate")]
692 | public void Error(string messageTemplate, T0 propertyValue0, T1 propertyValue1)
693 | => Write(LogEventLevel.Error, messageTemplate, propertyValue0, propertyValue1);
694 |
695 | ///
696 | /// Write a log event with the level.
697 | ///
698 | /// Message template describing the event.
699 | /// Object positionally formatted into the message template.
700 | /// Object positionally formatted into the message template.
701 | /// Object positionally formatted into the message template.
702 | ///
703 | /// Log.Error("Failed {ErrorCount} records.", brokenRecords.Length);
704 | ///
705 | [MessageTemplateFormatMethod("messageTemplate")]
706 | public void Error(string messageTemplate, T0 propertyValue0, T1 propertyValue1, T2 propertyValue2)
707 | => Write(LogEventLevel.Error, messageTemplate, propertyValue0, propertyValue1, propertyValue2);
708 |
709 | ///
710 | /// Write a log event with the level and associated exception.
711 | ///
712 | /// Message template describing the event.
713 | /// Objects positionally formatted into the message template.
714 | ///
715 | /// Log.Error("Failed {ErrorCount} records.", brokenRecords.Length);
716 | ///
717 | [MessageTemplateFormatMethod("messageTemplate")]
718 | public void Error(string messageTemplate, params object?[]? propertyValues)
719 | => Error((Exception?)null, messageTemplate, propertyValues);
720 |
721 | ///
722 | /// Write a log event with the level and associated exception.
723 | ///
724 | /// Exception related to the event.
725 | /// Message template describing the event.
726 | ///
727 | /// Log.Error(ex, "Failed {ErrorCount} records.", brokenRecords.Length);
728 | ///
729 | [MessageTemplateFormatMethod("messageTemplate")]
730 | public void Error(Exception? exception, string messageTemplate)
731 | => Write(LogEventLevel.Error, exception, messageTemplate, NoPropertyValues);
732 |
733 | ///
734 | /// Write a log event with the level and associated exception.
735 | ///
736 | /// Exception related to the event.
737 | /// Message template describing the event.
738 | /// Object positionally formatted into the message template.
739 | ///
740 | /// Log.Error(ex, "Failed {ErrorCount} records.", brokenRecords.Length);
741 | ///
742 | [MessageTemplateFormatMethod("messageTemplate")]
743 | public void Error(Exception? exception, string messageTemplate, T propertyValue)
744 | => Write(LogEventLevel.Error, exception, messageTemplate, propertyValue);
745 |
746 | ///
747 | /// Write a log event with the level and associated exception.
748 | ///
749 | /// Exception related to the event.
750 | /// Message template describing the event.
751 | /// Object positionally formatted into the message template.
752 | /// Object positionally formatted into the message template.
753 | ///
754 | /// Log.Error(ex, "Failed {ErrorCount} records.", brokenRecords.Length);
755 | ///
756 | [MessageTemplateFormatMethod("messageTemplate")]
757 | public void Error(Exception? exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1)
758 | => Write(LogEventLevel.Error, exception, messageTemplate, propertyValue0, propertyValue1);
759 |
760 | ///
761 | /// Write a log event with the level and associated exception.
762 | ///
763 | /// Exception related to the event.
764 | /// Message template describing the event.
765 | /// Object positionally formatted into the message template.
766 | /// Object positionally formatted into the message template.
767 | /// Object positionally formatted into the message template.
768 | ///
769 | /// Log.Error(ex, "Failed {ErrorCount} records.", brokenRecords.Length);
770 | ///
771 | [MessageTemplateFormatMethod("messageTemplate")]
772 | public void Error(Exception? exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1,
773 | T2 propertyValue2)
774 | => Write(LogEventLevel.Error, exception, messageTemplate, propertyValue0, propertyValue1, propertyValue2);
775 |
776 | ///
777 | /// Write a log event with the level and associated exception.
778 | ///
779 | /// Exception related to the event.
780 | /// Message template describing the event.
781 | /// Objects positionally formatted into the message template.
782 | ///
783 | /// Log.Error(ex, "Failed {ErrorCount} records.", brokenRecords.Length);
784 | ///
785 | [MessageTemplateFormatMethod("messageTemplate")]
786 | public void Error(Exception? exception, string messageTemplate, params object?[]? propertyValues)
787 | => Write(LogEventLevel.Error, exception, messageTemplate, propertyValues);
788 |
789 | ///
790 | /// Write a log event with the level.
791 | ///
792 | /// Message template describing the event.
793 | ///
794 | /// Log.Fatal("Process terminating.");
795 | ///
796 | [MessageTemplateFormatMethod("messageTemplate")]
797 | public void Fatal(string messageTemplate)
798 | => Write(LogEventLevel.Fatal, messageTemplate, NoPropertyValues);
799 |
800 | ///
801 | /// Write a log event with the level.
802 | ///
803 | /// Message template describing the event.
804 | /// Object positionally formatted into the message template.
805 | ///
806 | /// Log.Fatal("Process terminating.");
807 | ///
808 | [MessageTemplateFormatMethod("messageTemplate")]
809 | public void Fatal(string messageTemplate, T propertyValue)
810 | => Write(LogEventLevel.Fatal, messageTemplate, propertyValue);
811 |
812 | ///
813 | /// Write a log event with the level.
814 | ///
815 | /// Message template describing the event.
816 | /// Object positionally formatted into the message template.
817 | /// Object positionally formatted into the message template.
818 | ///
819 | /// Log.Fatal("Process terminating.");
820 | ///
821 | [MessageTemplateFormatMethod("messageTemplate")]
822 | public void Fatal(string messageTemplate, T0 propertyValue0, T1 propertyValue1)
823 | => Write(LogEventLevel.Fatal, messageTemplate, propertyValue0, propertyValue1);
824 |
825 | ///
826 | /// Write a log event with the level.
827 | ///
828 | /// Message template describing the event.
829 | /// Object positionally formatted into the message template.
830 | /// Object positionally formatted into the message template.
831 | /// Object positionally formatted into the message template.
832 | ///
833 | /// Log.Fatal("Process terminating.");
834 | ///
835 | [MessageTemplateFormatMethod("messageTemplate")]
836 | public void Fatal(string messageTemplate, T0 propertyValue0, T1 propertyValue1, T2 propertyValue2)
837 | => Write(LogEventLevel.Fatal, messageTemplate, propertyValue0, propertyValue1, propertyValue2);
838 |
839 | ///
840 | /// Write a log event with the level and associated exception.
841 | ///
842 | /// Message template describing the event.
843 | /// Objects positionally formatted into the message template.
844 | ///
845 | /// Log.Fatal("Process terminating.");
846 | ///
847 | [MessageTemplateFormatMethod("messageTemplate")]
848 | public void Fatal(string messageTemplate, params object?[]? propertyValues)
849 | => Fatal((Exception?)null, messageTemplate, propertyValues);
850 |
851 | ///
852 | /// Write a log event with the level and associated exception.
853 | ///
854 | /// Exception related to the event.
855 | /// Message template describing the event.
856 | ///
857 | /// Log.Fatal(ex, "Process terminating.");
858 | ///
859 | [MessageTemplateFormatMethod("messageTemplate")]
860 | public void Fatal(Exception? exception, string messageTemplate)
861 | => Write(LogEventLevel.Fatal, exception, messageTemplate, NoPropertyValues);
862 |
863 | ///
864 | /// Write a log event with the level and associated exception.
865 | ///
866 | /// Exception related to the event.
867 | /// Message template describing the event.
868 | /// Object positionally formatted into the message template.
869 | ///
870 | /// Log.Fatal(ex, "Process terminating.");
871 | ///
872 | [MessageTemplateFormatMethod("messageTemplate")]
873 | public void Fatal(Exception? exception, string messageTemplate, T propertyValue)
874 | => Write(LogEventLevel.Fatal, exception, messageTemplate, propertyValue);
875 |
876 | ///
877 | /// Write a log event with the level and associated exception.
878 | ///
879 | /// Exception related to the event.
880 | /// Message template describing the event.
881 | /// Object positionally formatted into the message template.
882 | /// Object positionally formatted into the message template.
883 | ///
884 | /// Log.Fatal(ex, "Process terminating.");
885 | ///
886 | [MessageTemplateFormatMethod("messageTemplate")]
887 | public void Fatal(Exception? exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1)
888 | => Write(LogEventLevel.Fatal, exception, messageTemplate, propertyValue0, propertyValue1);
889 |
890 | ///
891 | /// Write a log event with the level and associated exception.
892 | ///
893 | /// Exception related to the event.
894 | /// Message template describing the event.
895 | /// Object positionally formatted into the message template.
896 | /// Object positionally formatted into the message template.
897 | /// Object positionally formatted into the message template.
898 | ///
899 | /// Log.Fatal(ex, "Process terminating.");
900 | ///
901 | [MessageTemplateFormatMethod("messageTemplate")]
902 | public void Fatal(Exception? exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1,
903 | T2 propertyValue2)
904 | => Write(LogEventLevel.Fatal, exception, messageTemplate, propertyValue0, propertyValue1, propertyValue2);
905 |
906 | ///
907 | /// Write a log event with the level and associated exception.
908 | ///
909 | /// Exception related to the event.
910 | /// Message template describing the event.
911 | /// Objects positionally formatted into the message template.
912 | ///
913 | /// Log.Fatal(ex, "Process terminating.");
914 | ///
915 | [MessageTemplateFormatMethod("messageTemplate")]
916 | public void Fatal(Exception? exception, string messageTemplate, params object?[]? propertyValues)
917 | => Write(LogEventLevel.Fatal, exception, messageTemplate, propertyValues);
918 | }
--------------------------------------------------------------------------------
/src/Serilog.Extensions.Hosting/Extensions/Hosting/NullEnricher.cs:
--------------------------------------------------------------------------------
1 | // Copyright 2020 Serilog Contributors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | using Serilog.Core;
16 | using Serilog.Events;
17 |
18 | namespace Serilog.Extensions.Hosting;
19 |
20 | // Does nothing, but makes it easy to create an `ILogger` from a Serilog `Logger`
21 | // that will not dispose the underlying pipeline when disposed itself.
22 | class NullEnricher : ILogEventEnricher
23 | {
24 | public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
25 | {
26 | }
27 | }
--------------------------------------------------------------------------------
/src/Serilog.Extensions.Hosting/Extensions/Hosting/ReloadableLogger.cs:
--------------------------------------------------------------------------------
1 | // Copyright 2020 Serilog Contributors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | using System.Diagnostics.CodeAnalysis;
16 | using System.Runtime.CompilerServices;
17 | using Serilog.Core;
18 | using Serilog.Events;
19 |
20 | // ReSharper disable MemberCanBePrivate.Global
21 |
22 | namespace Serilog.Extensions.Hosting;
23 |
24 | ///
25 | /// A Serilog that can be reconfigured without invalidating existing
26 | /// instances derived from it.
27 | ///
28 | public sealed class ReloadableLogger : LoggerBase, ILogger, IReloadableLogger, IDisposable
29 | {
30 | readonly object _sync = new();
31 | Logger _logger;
32 |
33 | // One-way; if the value is `true` it can never again be made `false`, allowing "double-checked" reads. If
34 | // `true`, `_logger` is final and a memory barrier ensures the final value is seen by all threads.
35 | bool _frozen;
36 |
37 | // Unsure whether this should be exposed; currently going for minimal API surface.
38 | internal ReloadableLogger(Logger initial)
39 | {
40 | _logger = initial ?? throw new ArgumentNullException(nameof(initial));
41 | }
42 |
43 | ILogger IReloadableLogger.ReloadLogger()
44 | {
45 | return _logger;
46 | }
47 |
48 | ///
49 | /// Reload the logger using the supplied configuration delegate.
50 | ///
51 | /// A callback in which the logger is reconfigured.
52 | /// is null.
53 | public void Reload(Func configure)
54 | {
55 | if (configure == null) throw new ArgumentNullException(nameof(configure));
56 |
57 | lock (_sync)
58 | {
59 | _logger.Dispose();
60 | _logger = configure(new LoggerConfiguration()).CreateLogger();
61 | }
62 | }
63 |
64 | ///
65 | /// Freeze the logger, so that no further reconfiguration is possible. Once the logger is frozen, logging through
66 | /// new contextual loggers will have no additional cost, and logging directly through this logger will not require
67 | /// any synchronization.
68 | ///
69 | /// The configured with the final settings.
70 | /// The logger is already frozen.
71 | public Logger Freeze()
72 | {
73 | lock (_sync)
74 | {
75 | if (_frozen)
76 | throw new InvalidOperationException("The logger is already frozen.");
77 |
78 | _frozen = true;
79 |
80 | // https://github.com/dotnet/runtime/issues/20500#issuecomment-284774431
81 | // Publish `_logger` and `_frozen`. This is useful here because it means that once the logger is frozen - which
82 | // we always expect - reads don't require any synchronization/interlocked instructions.
83 | #if FEATURE_MBPW
84 | Interlocked.MemoryBarrierProcessWide();
85 | #else
86 | Thread.MemoryBarrier();
87 | #endif
88 |
89 | return _logger;
90 | }
91 | }
92 |
93 | ///
94 | public void Dispose()
95 | {
96 | lock (_sync)
97 | _logger.Dispose();
98 | }
99 |
100 | ///
101 | public ILogger ForContext(ILogEventEnricher enricher)
102 | {
103 | if (enricher == null!) return this;
104 |
105 | if (_frozen)
106 | return _logger.ForContext(enricher);
107 |
108 | lock (_sync)
109 | return new CachingReloadableLogger(this, _logger, this, p => p.ForContext(enricher));
110 | }
111 |
112 | ///
113 | public ILogger ForContext(IEnumerable enrichers)
114 | {
115 | if (enrichers == null!) return this;
116 |
117 | if (_frozen)
118 | return _logger.ForContext(enrichers);
119 |
120 | lock (_sync)
121 | return new CachingReloadableLogger(this, _logger, this, p => p.ForContext(enrichers));
122 | }
123 |
124 | ///
125 | public ILogger ForContext(string propertyName, object? value, bool destructureObjects = false)
126 | {
127 | if (propertyName == null!) return this;
128 |
129 | if (_frozen)
130 | return _logger.ForContext(propertyName, value, destructureObjects);
131 |
132 | lock (_sync)
133 | return new CachingReloadableLogger(this, _logger, this, p => p.ForContext(propertyName, value, destructureObjects));
134 | }
135 |
136 | ///
137 | public ILogger ForContext()
138 | {
139 | if (_frozen)
140 | return _logger.ForContext();
141 |
142 | lock (_sync)
143 | return new CachingReloadableLogger(this, _logger, this, p => p.ForContext());
144 | }
145 |
146 | ///
147 | public ILogger ForContext(Type source)
148 | {
149 | if (source == null!) return this;
150 |
151 | if (_frozen)
152 | return _logger.ForContext(source);
153 |
154 | lock (_sync)
155 | return new CachingReloadableLogger(this, _logger, this, p => p.ForContext(source));
156 | }
157 |
158 | ///
159 | public override void Write(LogEvent logEvent)
160 | {
161 | if (_frozen)
162 | {
163 | _logger.Write(logEvent);
164 | return;
165 | }
166 |
167 | lock (_sync)
168 | {
169 | _logger.Write(logEvent);
170 | }
171 | }
172 |
173 | ///
174 | public override void Write(LogEventLevel level, string messageTemplate)
175 | {
176 | if (_frozen)
177 | {
178 | _logger.Write(level, messageTemplate);
179 | return;
180 | }
181 |
182 | lock (_sync)
183 | {
184 | _logger.Write(level, messageTemplate);
185 | }
186 | }
187 |
188 | ///
189 | public override void Write(LogEventLevel level, string messageTemplate, T propertyValue)
190 | {
191 | if (_frozen)
192 | {
193 | _logger.Write(level, messageTemplate, propertyValue);
194 | return;
195 | }
196 |
197 | lock (_sync)
198 | {
199 | _logger.Write(level, messageTemplate, propertyValue);
200 | }
201 | }
202 |
203 | ///
204 | public override void Write(LogEventLevel level, string messageTemplate, T0 propertyValue0, T1 propertyValue1)
205 | {
206 | if (_frozen)
207 | {
208 | _logger.Write(level, messageTemplate, propertyValue0, propertyValue1);
209 | return;
210 | }
211 |
212 | lock (_sync)
213 | {
214 | _logger.Write(level, messageTemplate, propertyValue0, propertyValue1);
215 | }
216 | }
217 |
218 | ///
219 | public override void Write(LogEventLevel level, string messageTemplate, T0 propertyValue0, T1 propertyValue1,
220 | T2 propertyValue2)
221 | {
222 | if (_frozen)
223 | {
224 | _logger.Write(level, messageTemplate, propertyValue0, propertyValue1, propertyValue2);
225 | return;
226 | }
227 |
228 | lock (_sync)
229 | {
230 | _logger.Write(level, messageTemplate, propertyValue0, propertyValue1, propertyValue2);
231 | }
232 | }
233 |
234 | ///
235 | public override void Write(LogEventLevel level, string messageTemplate, params object?[]? propertyValues)
236 | {
237 | if (_frozen)
238 | {
239 | _logger.Write(level, messageTemplate, propertyValues);
240 | return;
241 | }
242 |
243 | lock (_sync)
244 | {
245 | _logger.Write(level, messageTemplate, propertyValues);
246 | }
247 | }
248 |
249 | ///
250 | public override void Write(LogEventLevel level, Exception? exception, string messageTemplate)
251 | {
252 | if (_frozen)
253 | {
254 | _logger.Write(level, exception, messageTemplate);
255 | return;
256 | }
257 |
258 | lock (_sync)
259 | {
260 | _logger.Write(level, exception, messageTemplate);
261 | }
262 | }
263 |
264 | ///
265 | public override void Write(LogEventLevel level, Exception? exception, string messageTemplate, T propertyValue)
266 | {
267 | if (_frozen)
268 | {
269 | _logger.Write(level, exception, messageTemplate, propertyValue);
270 | return;
271 | }
272 |
273 | lock (_sync)
274 | {
275 | _logger.Write(level, exception, messageTemplate, propertyValue);
276 | }
277 | }
278 |
279 | ///
280 | public override void Write(LogEventLevel level, Exception? exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1)
281 | {
282 | if (_frozen)
283 | {
284 | _logger.Write(level, exception, messageTemplate, propertyValue0, propertyValue1);
285 | return;
286 | }
287 |
288 | lock (_sync)
289 | {
290 | _logger.Write(level, exception, messageTemplate, propertyValue0, propertyValue1);
291 | }
292 | }
293 |
294 | ///
295 | public override void Write(LogEventLevel level, Exception? exception, string messageTemplate, T0 propertyValue0, T1 propertyValue1,
296 | T2 propertyValue2)
297 | {
298 | if (_frozen)
299 | {
300 | _logger.Write(level, exception, messageTemplate, propertyValue0, propertyValue1, propertyValue2);
301 | return;
302 | }
303 |
304 | lock (_sync)
305 | {
306 | _logger.Write(level, exception, messageTemplate, propertyValue0, propertyValue1, propertyValue2);
307 | }
308 | }
309 |
310 | ///
311 | public override void Write(LogEventLevel level, Exception? exception, string messageTemplate, params object?[]? propertyValues)
312 | {
313 | if (_frozen)
314 | {
315 | _logger.Write(level, exception, messageTemplate, propertyValues);
316 | return;
317 | }
318 |
319 | lock (_sync)
320 | {
321 | _logger.Write(level, exception, messageTemplate, propertyValues);
322 | }
323 | }
324 |
325 | ///
326 | public bool IsEnabled(LogEventLevel level)
327 | {
328 | if (_frozen)
329 | {
330 | return _logger.IsEnabled(level);
331 | }
332 |
333 | lock (_sync)
334 | {
335 | return _logger.IsEnabled(level);
336 | }
337 | }
338 |
339 | ///
340 | public bool BindMessageTemplate(string messageTemplate, object?[]? propertyValues,
341 | [NotNullWhen(true)]
342 | out MessageTemplate? parsedTemplate,
343 | [NotNullWhen(true)]
344 | out IEnumerable? boundProperties)
345 | {
346 | if (_frozen)
347 | {
348 | return _logger.BindMessageTemplate(messageTemplate, propertyValues, out parsedTemplate, out boundProperties);
349 | }
350 |
351 | lock (_sync)
352 | {
353 | return _logger.BindMessageTemplate(messageTemplate, propertyValues, out parsedTemplate, out boundProperties);
354 | }
355 | }
356 |
357 | ///
358 | public bool BindProperty(string? propertyName, object? value, bool destructureObjects, [NotNullWhen(true)] out LogEventProperty? property)
359 | {
360 | if (_frozen)
361 | {
362 | return _logger.BindProperty(propertyName, value, destructureObjects, out property);
363 | }
364 |
365 | lock (_sync)
366 | {
367 | return _logger.BindProperty(propertyName, value, destructureObjects, out property);
368 | }
369 | }
370 |
371 | // `newRoot` is null when the second returned tuple argument is `false`, but the signature of the method doesn't currently
372 | // allow this to be expressed.
373 | [MethodImpl(MethodImplOptions.AggressiveInlining)]
374 | (ILogger, bool) UpdateForCaller(ILogger root, ILogger? cached, IReloadableLogger caller, out ILogger newRoot, out ILogger? newCached, out bool frozen)
375 | {
376 | // Synchronization on `_sync` is not required in this method; it will be called without a lock
377 | // if `_frozen` and under a lock if not.
378 |
379 | if (_frozen)
380 | {
381 | // If we're frozen, then the caller hasn't observed this yet and should update. We could optimize a little here
382 | // and only signal an update if the cached logger is stale (as per the next condition below).
383 | newRoot = _logger;
384 | newCached = caller.ReloadLogger();
385 | frozen = true;
386 | return (newCached, true);
387 | }
388 |
389 | if (cached != null! && root == _logger)
390 | {
391 | newRoot = default!;
392 | newCached = default;
393 | frozen = false;
394 | return (cached, false);
395 | }
396 |
397 | newRoot = _logger;
398 | newCached = caller.ReloadLogger();
399 | frozen = false;
400 | return (newCached, true);
401 | }
402 |
403 | internal bool InvokeIsEnabled(ILogger root, ILogger? cached, IReloadableLogger caller, LogEventLevel level, out bool isEnabled, out ILogger newRoot, out ILogger? newCached, out bool frozen)
404 | {
405 | if (_frozen)
406 | {
407 | var (logger, update) = UpdateForCaller(root, cached, caller, out newRoot, out newCached, out frozen);
408 | isEnabled = logger.IsEnabled(level);
409 | return update;
410 | }
411 |
412 | lock (_sync)
413 | {
414 | var (logger, update) = UpdateForCaller(root, cached, caller, out newRoot, out newCached, out frozen);
415 | isEnabled = logger.IsEnabled(level);
416 | return update;
417 | }
418 | }
419 |
420 | internal bool InvokeBindMessageTemplate(ILogger root, ILogger? cached, IReloadableLogger caller, string messageTemplate,
421 | object?[]? propertyValues, [NotNullWhen(true)] out MessageTemplate? parsedTemplate, [NotNullWhen(true)] out IEnumerable? boundProperties,
422 | out bool canBind, out ILogger newRoot, out ILogger? newCached, out bool frozen)
423 | {
424 | if (_frozen)
425 | {
426 | var (logger, update) = UpdateForCaller(root, cached, caller, out newRoot, out newCached, out frozen);
427 | canBind = logger.BindMessageTemplate(messageTemplate, propertyValues, out parsedTemplate, out boundProperties);
428 | return update;
429 | }
430 |
431 | lock (_sync)
432 | {
433 | var (logger, update) = UpdateForCaller(root, cached, caller, out newRoot, out newCached, out frozen);
434 | canBind = logger.BindMessageTemplate(messageTemplate, propertyValues, out parsedTemplate, out boundProperties);
435 | return update;
436 | }
437 | }
438 |
439 | internal bool InvokeBindProperty(ILogger root, ILogger? cached, IReloadableLogger caller, string? propertyName,
440 | object? propertyValue, bool destructureObjects, [NotNullWhen(true)] out LogEventProperty? property,
441 | out bool canBind, out ILogger newRoot, out ILogger? newCached, out bool frozen)
442 | {
443 | if (_frozen)
444 | {
445 | var (logger, update) = UpdateForCaller(root, cached, caller, out newRoot, out newCached, out frozen);
446 | canBind = logger.BindProperty(propertyName, propertyValue, destructureObjects, out property);
447 | return update;
448 | }
449 |
450 | lock (_sync)
451 | {
452 | var (logger, update) = UpdateForCaller(root, cached, caller, out newRoot, out newCached, out frozen);
453 | canBind = logger.BindProperty(propertyName, propertyValue, destructureObjects, out property);
454 | return update;
455 | }
456 | }
457 |
458 | internal bool InvokeWrite(ILogger root, ILogger? cached, IReloadableLogger caller, LogEvent logEvent, out ILogger newRoot, out ILogger? newCached, out bool frozen)
459 | {
460 | if (_frozen)
461 | {
462 | var (logger, update) = UpdateForCaller(root, cached, caller, out newRoot, out newCached, out frozen);
463 | logger.Write(logEvent);
464 | return update;
465 | }
466 |
467 | lock (_sync)
468 | {
469 | var (logger, update) = UpdateForCaller(root, cached, caller, out newRoot, out newCached, out frozen);
470 | logger.Write(logEvent);
471 | return update;
472 | }
473 | }
474 |
475 | internal bool InvokeWrite(ILogger root, ILogger? cached, IReloadableLogger caller, LogEventLevel level, string messageTemplate,
476 | out ILogger newRoot, out ILogger? newCached, out bool frozen)
477 | {
478 | if (_frozen)
479 | {
480 | var (logger, update) = UpdateForCaller(root, cached, caller, out newRoot, out newCached, out frozen);
481 | logger.Write(level, messageTemplate);
482 | return update;
483 | }
484 |
485 | lock (_sync)
486 | {
487 | var (logger, update) = UpdateForCaller(root, cached, caller, out newRoot, out newCached, out frozen);
488 | logger.Write(level, messageTemplate);
489 | return update;
490 | }
491 | }
492 |
493 | internal bool InvokeWrite(ILogger root, ILogger? cached, IReloadableLogger caller, LogEventLevel level, string messageTemplate,
494 | T propertyValue,
495 | out ILogger newRoot, out ILogger? newCached, out bool frozen)
496 | {
497 | if (_frozen)
498 | {
499 | var (logger, update) = UpdateForCaller(root, cached, caller, out newRoot, out newCached, out frozen);
500 | logger.Write(level, messageTemplate, propertyValue);
501 | return update;
502 | }
503 |
504 | lock (_sync)
505 | {
506 | var (logger, update) = UpdateForCaller(root, cached, caller, out newRoot, out newCached, out frozen);
507 | logger.Write(level, messageTemplate, propertyValue);
508 | return update;
509 | }
510 | }
511 |
512 | internal bool InvokeWrite(ILogger root, ILogger? cached, IReloadableLogger caller, LogEventLevel level, string messageTemplate,
513 | T0 propertyValue0, T1 propertyValue1,
514 | out ILogger newRoot, out ILogger? newCached, out bool frozen)
515 | {
516 | if (_frozen)
517 | {
518 | var (logger, update) = UpdateForCaller(root, cached, caller, out newRoot, out newCached, out frozen);
519 | logger.Write(level, messageTemplate, propertyValue0, propertyValue1);
520 | return update;
521 | }
522 |
523 | lock (_sync)
524 | {
525 | var (logger, update) = UpdateForCaller(root, cached, caller, out newRoot, out newCached, out frozen);
526 | logger.Write(level, messageTemplate, propertyValue0, propertyValue1);
527 | return update;
528 | }
529 | }
530 |
531 | internal bool InvokeWrite(ILogger root, ILogger? cached, IReloadableLogger caller, LogEventLevel level, string messageTemplate,
532 | T0 propertyValue0, T1 propertyValue1, T2 propertyValue2,
533 | out ILogger newRoot, out ILogger? newCached, out bool frozen)
534 | {
535 | if (_frozen)
536 | {
537 | var (logger, update) = UpdateForCaller(root, cached, caller, out newRoot, out newCached, out frozen);
538 | logger.Write(level, messageTemplate, propertyValue0, propertyValue1, propertyValue2);
539 | return update;
540 | }
541 |
542 | lock (_sync)
543 | {
544 | var (logger, update) = UpdateForCaller(root, cached, caller, out newRoot, out newCached, out frozen);
545 | logger.Write(level, messageTemplate, propertyValue0, propertyValue1, propertyValue2);
546 | return update;
547 | }
548 | }
549 |
550 | internal bool InvokeWrite(ILogger root, ILogger? cached, IReloadableLogger caller, LogEventLevel level, string messageTemplate,
551 | object?[]? propertyValues,
552 | out ILogger newRoot, out ILogger? newCached, out bool frozen)
553 | {
554 | if (_frozen)
555 | {
556 | var (logger, update) = UpdateForCaller(root, cached, caller, out newRoot, out newCached, out frozen);
557 | logger.Write(level, messageTemplate, propertyValues);
558 | return update;
559 | }
560 |
561 | lock (_sync)
562 | {
563 | var (logger, update) = UpdateForCaller(root, cached, caller, out newRoot, out newCached, out frozen);
564 | logger.Write(level, messageTemplate, propertyValues);
565 | return update;
566 | }
567 | }
568 |
569 | internal bool InvokeWrite(ILogger root, ILogger? cached, IReloadableLogger caller, LogEventLevel level, Exception? exception, string messageTemplate,
570 | out ILogger newRoot, out ILogger? newCached, out bool frozen)
571 | {
572 | if (_frozen)
573 | {
574 | var (logger, update) = UpdateForCaller(root, cached, caller, out newRoot, out newCached, out frozen);
575 | logger.Write(level, exception, messageTemplate);
576 | return update;
577 | }
578 |
579 | lock (_sync)
580 | {
581 | var (logger, update) = UpdateForCaller(root, cached, caller, out newRoot, out newCached, out frozen);
582 | logger.Write(level, exception, messageTemplate);
583 | return update;
584 | }
585 | }
586 |
587 | internal bool InvokeWrite(ILogger root, ILogger? cached, IReloadableLogger caller, LogEventLevel level, Exception? exception, string messageTemplate,
588 | T propertyValue,
589 | out ILogger newRoot, out ILogger? newCached, out bool frozen)
590 | {
591 | if (_frozen)
592 | {
593 | var (logger, update) = UpdateForCaller(root, cached, caller, out newRoot, out newCached, out frozen);
594 | logger.Write(level, exception, messageTemplate, propertyValue);
595 | return update;
596 | }
597 |
598 | lock (_sync)
599 | {
600 | var (logger, update) = UpdateForCaller(root, cached, caller, out newRoot, out newCached, out frozen);
601 | logger.Write(level, exception, messageTemplate, propertyValue);
602 | return update;
603 | }
604 | }
605 |
606 | internal bool InvokeWrite(ILogger root, ILogger? cached, IReloadableLogger caller, LogEventLevel level, Exception? exception, string messageTemplate,
607 | T0 propertyValue0, T1 propertyValue1,
608 | out ILogger newRoot, out ILogger? newCached, out bool frozen)
609 | {
610 | if (_frozen)
611 | {
612 | var (logger, update) = UpdateForCaller(root, cached, caller, out newRoot, out newCached, out frozen);
613 | logger.Write(level, exception, messageTemplate, propertyValue0, propertyValue1);
614 | return update;
615 | }
616 |
617 | lock (_sync)
618 | {
619 | var (logger, update) = UpdateForCaller(root, cached, caller, out newRoot, out newCached, out frozen);
620 | logger.Write(level, exception, messageTemplate, propertyValue0, propertyValue1);
621 | return update;
622 | }
623 | }
624 |
625 | internal bool InvokeWrite(ILogger root, ILogger? cached, IReloadableLogger caller, LogEventLevel level, Exception? exception, string messageTemplate,
626 | T0 propertyValue0, T1 propertyValue1, T2 propertyValue2,
627 | out ILogger newRoot, out ILogger? newCached, out bool frozen)
628 | {
629 | if (_frozen)
630 | {
631 | var (logger, update) = UpdateForCaller(root, cached, caller, out newRoot, out newCached, out frozen);
632 | logger.Write(level, exception, messageTemplate, propertyValue0, propertyValue1, propertyValue2);
633 | return update;
634 | }
635 |
636 | lock (_sync)
637 | {
638 | var (logger, update) = UpdateForCaller(root, cached, caller, out newRoot, out newCached, out frozen);
639 | logger.Write(level, exception, messageTemplate, propertyValue0, propertyValue1, propertyValue2);
640 | return update;
641 | }
642 | }
643 |
644 | internal bool InvokeWrite(ILogger root, ILogger? cached, IReloadableLogger caller, LogEventLevel level, Exception? exception, string messageTemplate,
645 | object?[]? propertyValues,
646 | out ILogger newRoot, out ILogger? newCached, out bool frozen)
647 | {
648 | if (_frozen)
649 | {
650 | var (logger, update) = UpdateForCaller(root, cached, caller, out newRoot, out newCached, out frozen);
651 | logger.Write(level, exception, messageTemplate, propertyValues);
652 | return update;
653 | }
654 |
655 | lock (_sync)
656 | {
657 | var (logger, update) = UpdateForCaller(root, cached, caller, out newRoot, out newCached, out frozen);
658 | logger.Write(level, exception, messageTemplate, propertyValues);
659 | return update;
660 | }
661 | }
662 |
663 | internal bool CreateChild(
664 | ILogger root,
665 | IReloadableLogger parent,
666 | ILogger? cachedParent,
667 | Func configureChild,
668 | out ILogger child,
669 | out ILogger newRoot,
670 | out ILogger? newCached,
671 | out bool frozen)
672 | {
673 | if (_frozen)
674 | {
675 | var (logger, _) = UpdateForCaller(root, cachedParent, parent, out newRoot, out newCached, out frozen);
676 | child = configureChild(logger);
677 | return true; // Always an update, since the caller has not observed that the reloadable logger is frozen.
678 | }
679 |
680 | // No synchronization, here - a lot of loggers are created and thrown away again without ever being used,
681 | // so we just return a lazy wrapper.
682 | child = new CachingReloadableLogger(this, root, parent, configureChild);
683 | newRoot = default!;
684 | newCached = default;
685 | frozen = default;
686 | return false;
687 | }
688 | }
689 |
--------------------------------------------------------------------------------
/src/Serilog.Extensions.Hosting/IDiagnosticContext.cs:
--------------------------------------------------------------------------------
1 | // Copyright 2019 Serilog Contributors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | using System;
16 |
17 | namespace Serilog;
18 |
19 | ///
20 | /// Collects diagnostic information for packaging into wide events.
21 | ///
22 | public interface IDiagnosticContext
23 | {
24 | ///
25 | /// Set the specified property on the current diagnostic context. The property will be collected
26 | /// and attached to the event emitted at the completion of the context.
27 | ///
28 | /// The name of the property. Must be non-empty.
29 | /// The property value.
30 | /// If true, the value will be serialized as structured
31 | /// data if possible; if false, the object will be recorded as a scalar or simple array.
32 | void Set(string propertyName, object? value, bool destructureObjects = false);
33 |
34 | ///
35 | /// Set the specified exception on the current diagnostic context.
36 | ///
37 | ///
38 | /// This method is useful when unhandled exceptions do not reach Serilog.AspNetCore.RequestLoggingMiddleware,
39 | /// such as when using Hellang.Middleware.ProblemDetails
40 | /// to transform exceptions to ProblemDetails responses.
41 | ///
42 | /// The exception to log. If null is given, it clears any previously assigned exception.
43 | void SetException(Exception exception);
44 | }
45 |
--------------------------------------------------------------------------------
/src/Serilog.Extensions.Hosting/LoggerConfigurationExtensions.cs:
--------------------------------------------------------------------------------
1 | // Copyright 2020 Serilog Contributors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #if !NO_RELOADABLE_LOGGER
16 |
17 | using Microsoft.Extensions.Hosting;
18 | using Serilog.Extensions.Hosting;
19 | using System;
20 |
21 | namespace Serilog;
22 |
23 | ///
24 | /// Extends .
25 | ///
26 | public static class LoggerConfigurationExtensions
27 | {
28 | ///
29 | /// Create a for use during host bootstrapping. The
30 | ///
31 | /// configuration overload will detect when is set to a instance, and
32 | /// reconfigure/freeze it so that s created during host bootstrapping continue to work once
33 | /// logger configuration (with access to host services) is completed.
34 | ///
35 | ///
36 | ///
37 | public static ReloadableLogger CreateBootstrapLogger(this LoggerConfiguration loggerConfiguration)
38 | {
39 | return new ReloadableLogger(loggerConfiguration.CreateLogger());
40 | }
41 | }
42 |
43 | #endif
44 |
--------------------------------------------------------------------------------
/src/Serilog.Extensions.Hosting/LoggerSettingsConfigurationExtensions.cs:
--------------------------------------------------------------------------------
1 | // Copyright 2020 Serilog Contributors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | using System;
16 | using Serilog.Configuration;
17 | using Serilog.Core;
18 | using Serilog.Extensions.Hosting;
19 |
20 | namespace Serilog;
21 |
22 | ///
23 | /// Extends with methods for consuming host services.
24 | ///
25 | public static class LoggerSettingsConfigurationExtensions
26 | {
27 | ///
28 | /// Configure the logger using components from the . If present, the logger will
29 | /// receive implementations/instances of , ,
30 | /// , , , and
31 | /// .
32 | ///
33 | /// The `ReadFrom` configuration object.
34 | /// A from which services will be requested.
35 | /// A to support method chaining.
36 | public static LoggerConfiguration Services(
37 | this LoggerSettingsConfiguration loggerSettingsConfiguration,
38 | IServiceProvider services)
39 | {
40 | return loggerSettingsConfiguration.Settings(new InjectedLoggerSettings(services));
41 | }
42 | }
--------------------------------------------------------------------------------
/src/Serilog.Extensions.Hosting/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.CompilerServices;
2 |
3 | [assembly: InternalsVisibleTo("Serilog.Extensions.Hosting.Tests, PublicKey=" +
4 | "0024000004800000940000000602000000240000525341310004000001000100fb8d13fd344a1c" +
5 | "6fe0fe83ef33c1080bf30690765bc6eb0df26ebfdf8f21670c64265b30db09f73a0dea5b3db4c9" +
6 | "d18dbf6d5a25af5ce9016f281014d79dc3b4201ac646c451830fc7e61a2dfd633d34c39f87b818" +
7 | "94191652df5ac63cc40c77f3542f702bda692e6e8a9158353df189007a49da0f3cfd55eb250066" +
8 | "b19485ec")]
9 |
--------------------------------------------------------------------------------
/src/Serilog.Extensions.Hosting/Serilog.Extensions.Hosting.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Serilog support for .NET Core logging in hosted services
5 | Microsoft;Serilog Contributors
6 |
8 | net462;netstandard2.0;netstandard2.1;net8.0;net9.0
9 | serilog;aspnet;aspnetcore;hosting
10 | icon.png
11 | https://github.com/serilog/serilog-extensions-hosting
12 | Apache-2.0
13 | Serilog
14 | README.md
15 |
16 |
17 |
18 | $(DefineConstants);FEATURE_MBPW
19 |
20 |
21 |
22 | $(DefineConstants);FEATURE_MBPW
23 |
24 |
25 |
26 | $(DefineConstants);FEATURE_MBPW
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/src/Serilog.Extensions.Hosting/SerilogHostBuilderExtensions.cs:
--------------------------------------------------------------------------------
1 | // Copyright 2020 Serilog Contributors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | using System;
16 | using Microsoft.Extensions.Hosting;
17 | using Microsoft.Extensions.Logging;
18 | using Serilog.Extensions.Logging;
19 | // ReSharper disable MemberCanBePrivate.Global
20 |
21 | namespace Serilog;
22 |
23 | ///
24 | /// Extends with Serilog configuration methods.
25 | ///
26 | public static class SerilogHostBuilderExtensions
27 | {
28 | ///
29 | /// Sets Serilog as the logging provider.
30 | ///
31 | /// The host builder to configure.
32 | /// The Serilog logger; if not supplied, the static will be used.
33 | /// When true, dispose when the framework disposes the provider. If the
34 | /// logger is not specified but is true, the method will be
35 | /// called on the static class instead.
36 | /// A registered in the Serilog pipeline using the
37 | /// WriteTo.Providers() configuration method, enabling other s to receive events. By
38 | /// default, only Serilog sinks will receive events.
39 | /// The host builder.
40 | public static IHostBuilder UseSerilog(
41 | this IHostBuilder builder,
42 | ILogger? logger = null,
43 | bool dispose = false,
44 | LoggerProviderCollection? providers = null)
45 | {
46 | if (builder == null) throw new ArgumentNullException(nameof(builder));
47 |
48 | builder.ConfigureServices((_, collection) =>
49 | {
50 | collection.AddSerilog(logger, dispose, providers);
51 | });
52 |
53 | return builder;
54 | }
55 |
56 | /// Sets Serilog as the logging provider.
57 | ///
58 | /// A is supplied so that configuration and hosting information can be used.
59 | /// The logger will be shut down when application services are disposed.
60 | ///
61 | /// The host builder to configure.
62 | /// The delegate for configuring the that will be used to construct a .
63 | /// Indicates whether to preserve the value of .
64 | /// By default, Serilog does not write events to s registered through
65 | /// the Microsoft.Extensions.Logging API. Normally, equivalent Serilog sinks are used in place of providers. Specify
66 | /// true to write events to all providers.
67 | /// The host builder.
68 | public static IHostBuilder UseSerilog(
69 | this IHostBuilder builder,
70 | Action configureLogger,
71 | bool preserveStaticLogger = false,
72 | bool writeToProviders = false)
73 | {
74 | if (builder == null) throw new ArgumentNullException(nameof(builder));
75 | if (configureLogger == null) throw new ArgumentNullException(nameof(configureLogger));
76 | return UseSerilog(
77 | builder,
78 | (hostBuilderContext, services, loggerConfiguration) =>
79 | configureLogger(hostBuilderContext, loggerConfiguration),
80 | preserveStaticLogger: preserveStaticLogger,
81 | writeToProviders: writeToProviders);
82 | }
83 |
84 | /// Sets Serilog as the logging provider.
85 | ///
86 | /// A is supplied so that configuration and hosting information can be used.
87 | /// The logger will be shut down when application services are disposed.
88 | ///
89 | /// The host builder to configure.
90 | /// The delegate for configuring the that will be used to construct a .
91 | /// Indicates whether to preserve the value of .
92 | /// By default, Serilog does not write events to s registered through
93 | /// the Microsoft.Extensions.Logging API. Normally, equivalent Serilog sinks are used in place of providers. Specify
94 | /// true to write events to all providers.
95 | /// If the static is a bootstrap logger (see
96 | /// LoggerConfigurationExtensions.CreateBootstrapLogger()), and is
97 | /// not specified, the the bootstrap logger will be reconfigured through the supplied delegate, rather than being
98 | /// replaced entirely or ignored.
99 | /// The host builder.
100 | public static IHostBuilder UseSerilog(
101 | this IHostBuilder builder,
102 | Action configureLogger,
103 | bool preserveStaticLogger = false,
104 | bool writeToProviders = false)
105 | {
106 | if (builder == null) throw new ArgumentNullException(nameof(builder));
107 | if (configureLogger == null) throw new ArgumentNullException(nameof(configureLogger));
108 |
109 | builder.ConfigureServices((context, collection) =>
110 | {
111 | collection.AddSerilog(
112 | (services, loggerConfiguration) =>
113 | configureLogger(context, services, loggerConfiguration),
114 | preserveStaticLogger: preserveStaticLogger,
115 | writeToProviders: writeToProviders);
116 | });
117 |
118 | return builder;
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/src/Serilog.Extensions.Hosting/SerilogServiceCollectionExtensions.cs:
--------------------------------------------------------------------------------
1 | // Copyright 2020 Serilog Contributors
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | using Microsoft.Extensions.DependencyInjection;
16 | using Microsoft.Extensions.Logging;
17 | using Serilog.Extensions.Hosting;
18 | using Serilog.Extensions.Logging;
19 | // ReSharper disable MemberCanBePrivate.Global
20 |
21 | namespace Serilog;
22 |
23 | ///
24 | /// Extends with Serilog configuration methods.
25 | ///
26 | public static class SerilogServiceCollectionExtensions
27 | {
28 | // Used internally to pass information through the container. We need to do this because if `logger` is the
29 | // root logger, registering it as a singleton may lead to disposal along with the container by MEDI. This isn't
30 | // always desirable, i.e. we may be handed a logger and `dispose: false`, so wrapping it keeps us in control
31 | // of when the logger is disposed.
32 | class RegisteredLogger
33 | {
34 | public RegisteredLogger(ILogger logger)
35 | {
36 | Logger = logger;
37 | }
38 |
39 | public ILogger Logger { get; }
40 | }
41 |
42 | ///
43 | /// Sets Serilog as the logging provider.
44 | ///
45 | /// The service collection to use.
46 | /// The Serilog logger; if not supplied, the static will be used.
47 | /// When true, dispose when the framework disposes the provider. If the
48 | /// logger is not specified but is true, the method will be
49 | /// called on the static class instead.
50 | /// A registered in the Serilog pipeline using the
51 | /// WriteTo.Providers() configuration method, enabling other s to receive events. By
52 | /// default, only Serilog sinks will receive events.
53 | /// The service collection.
54 | public static IServiceCollection AddSerilog(
55 | this IServiceCollection collection,
56 | ILogger? logger = null,
57 | bool dispose = false,
58 | LoggerProviderCollection? providers = null)
59 | {
60 | if (collection == null) throw new ArgumentNullException(nameof(collection));
61 |
62 | if (providers != null)
63 | {
64 | collection.AddSingleton(services =>
65 | {
66 | var factory = new SerilogLoggerFactory(logger, dispose, providers);
67 |
68 | foreach (var provider in services.GetServices())
69 | factory.AddProvider(provider);
70 |
71 | return factory;
72 | });
73 | }
74 | else
75 | {
76 | collection.AddSingleton(_ => new SerilogLoggerFactory(logger, dispose));
77 | }
78 |
79 | if (logger != null)
80 | {
81 | // This won't (and shouldn't) take ownership of the logger.
82 | collection.AddSingleton(logger);
83 |
84 | // Still need to use RegisteredLogger as it is used by ConfigureDiagnosticContext.
85 | collection.AddSingleton(new RegisteredLogger(logger));
86 | }
87 | bool useRegisteredLogger = logger != null;
88 | ConfigureDiagnosticContext(collection, useRegisteredLogger);
89 |
90 | return collection;
91 | }
92 |
93 | /// Sets Serilog as the logging provider.
94 | /// The service collection to use.
95 | /// The delegate for configuring the that will be used to construct a .
96 | /// Indicates whether to preserve the value of .
97 | /// By default, Serilog does not write events to s registered through
98 | /// the Microsoft.Extensions.Logging API. Normally, equivalent Serilog sinks are used in place of providers. Specify
99 | /// true to write events to all providers.
100 | /// The service collection.
101 | public static IServiceCollection AddSerilog(
102 | this IServiceCollection collection,
103 | Action configureLogger,
104 | bool preserveStaticLogger = false,
105 | bool writeToProviders = false)
106 | {
107 | if (collection == null) throw new ArgumentNullException(nameof(collection));
108 | if (configureLogger == null) throw new ArgumentNullException(nameof(configureLogger));
109 | return AddSerilog(
110 | collection,
111 | (_, loggerConfiguration) =>
112 | configureLogger(loggerConfiguration),
113 | preserveStaticLogger: preserveStaticLogger,
114 | writeToProviders: writeToProviders);
115 | }
116 |
117 | /// Sets Serilog as the logging provider.
118 | /// The service collection to use.
119 | /// The delegate for configuring the that will be used to construct a .
120 | /// Indicates whether to preserve the value of .
121 | /// By default, Serilog does not write events to s registered through
122 | /// the Microsoft.Extensions.Logging API. Normally, equivalent Serilog sinks are used in place of providers. Specify
123 | /// true to write events to all providers.
124 | /// If the static is a bootstrap logger (see
125 | /// LoggerConfigurationExtensions.CreateBootstrapLogger()), and is
126 | /// not specified, the the bootstrap logger will be reconfigured through the supplied delegate, rather than being
127 | /// replaced entirely or ignored.
128 | /// The service collection.
129 | public static IServiceCollection AddSerilog(
130 | this IServiceCollection collection,
131 | Action configureLogger,
132 | bool preserveStaticLogger = false,
133 | bool writeToProviders = false)
134 | {
135 | if (collection == null) throw new ArgumentNullException(nameof(collection));
136 | if (configureLogger == null) throw new ArgumentNullException(nameof(configureLogger));
137 |
138 | // This check is eager; replacing the bootstrap logger after calling this method is not supported.
139 | var reloadable = Log.Logger as ReloadableLogger;
140 | var useReload = reloadable != null && !preserveStaticLogger;
141 |
142 | LoggerProviderCollection? loggerProviders = null;
143 | if (writeToProviders)
144 | {
145 | loggerProviders = new LoggerProviderCollection();
146 | }
147 |
148 | collection.AddSingleton(services =>
149 | {
150 | ILogger logger;
151 | if (useReload)
152 | {
153 | reloadable!.Reload(cfg =>
154 | {
155 | if (loggerProviders != null)
156 | cfg.WriteTo.Providers(loggerProviders);
157 |
158 | configureLogger(services, cfg);
159 | return cfg;
160 | });
161 |
162 | logger = reloadable.Freeze();
163 | }
164 | else
165 | {
166 | var loggerConfiguration = new LoggerConfiguration();
167 |
168 | if (loggerProviders != null)
169 | loggerConfiguration.WriteTo.Providers(loggerProviders);
170 |
171 | configureLogger(services, loggerConfiguration);
172 | logger = loggerConfiguration.CreateLogger();
173 | }
174 |
175 | return new RegisteredLogger(logger);
176 | });
177 |
178 | collection.AddSingleton(services =>
179 | {
180 | // How can we register the logger, here, but not have MEDI dispose it?
181 | // Using the `NullEnricher` hack to prevent disposal.
182 | var logger = services.GetRequiredService().Logger;
183 | return logger.ForContext(new NullEnricher());
184 | });
185 |
186 | collection.AddSingleton(services =>
187 | {
188 | var logger = services.GetRequiredService().Logger;
189 |
190 | ILogger? registeredLogger = null;
191 | if (preserveStaticLogger)
192 | {
193 | registeredLogger = logger;
194 | }
195 | else
196 | {
197 | // Passing a `null` logger to `SerilogLoggerFactory` results in disposal via
198 | // `Log.CloseAndFlush()`, which additionally replaces the static logger with a no-op.
199 | Log.Logger = logger;
200 | }
201 |
202 | var factory = new SerilogLoggerFactory(registeredLogger, !useReload, loggerProviders);
203 |
204 | if (writeToProviders)
205 | {
206 | foreach (var provider in services.GetServices())
207 | factory.AddProvider(provider);
208 | }
209 |
210 | return factory;
211 | });
212 |
213 | ConfigureDiagnosticContext(collection, preserveStaticLogger);
214 |
215 | return collection;
216 | }
217 |
218 | static void ConfigureDiagnosticContext(IServiceCollection collection, bool useRegisteredLogger)
219 | {
220 | if (collection == null) throw new ArgumentNullException(nameof(collection));
221 |
222 | // Registered to provide two services...
223 | // Consumed by e.g. middleware
224 | collection.AddSingleton(services =>
225 | {
226 | ILogger? logger = useRegisteredLogger ? services.GetRequiredService().Logger : null;
227 | return new DiagnosticContext(logger);
228 | });
229 | // Consumed by user code
230 | collection.AddSingleton(services => services.GetRequiredService());
231 | }
232 | }
233 |
--------------------------------------------------------------------------------
/test/Serilog.Extensions.Hosting.Tests/DiagnosticContextTests.cs:
--------------------------------------------------------------------------------
1 | using Serilog.Events;
2 | using Serilog.Extensions.Hosting.Tests.Support;
3 | using Xunit;
4 |
5 | // ReSharper disable PossibleNullReferenceException
6 |
7 | namespace Serilog.Extensions.Hosting.Tests;
8 |
9 | public class DiagnosticContextTests
10 | {
11 | [Fact]
12 | public void SetIsSafeWhenNoContextIsActive()
13 | {
14 | var dc = new DiagnosticContext(Some.Logger());
15 | dc.Set(Some.String("name"), Some.Int32());
16 | }
17 |
18 | [Fact]
19 | public void SetExceptionIsSafeWhenNoContextIsActive()
20 | {
21 | var dc = new DiagnosticContext(Some.Logger());
22 | dc.SetException(new Exception("test"));
23 | }
24 |
25 | [Fact]
26 | public async Task PropertiesAreCollectedInAnActiveContext()
27 | {
28 | var dc = new DiagnosticContext(Some.Logger());
29 |
30 | var collector = dc.BeginCollection();
31 | dc.Set(Some.String("first"), Some.Int32());
32 | await Task.Delay(TimeSpan.FromMilliseconds(10));
33 | dc.Set(Some.String("second"), Some.Int32());
34 |
35 | Assert.True(collector.TryComplete(out var properties, out var exception));
36 | Assert.Equal(2, properties!.Count());
37 | Assert.Null(exception);
38 |
39 | Assert.False(collector.TryComplete(out _, out _));
40 |
41 | collector.Dispose();
42 |
43 | dc.Set(Some.String("third"), Some.Int32());
44 | Assert.False(collector.TryComplete(out _, out _));
45 | }
46 |
47 | [Fact]
48 | public void ExceptionIsCollectedInAnActiveContext()
49 | {
50 | var dc = new DiagnosticContext(Some.Logger());
51 | var collector = dc.BeginCollection();
52 |
53 | var setException = new Exception("before collect");
54 | dc.SetException(setException);
55 |
56 | Assert.True(collector.TryComplete(out _, out var collectedException));
57 | Assert.Same(setException, collectedException);
58 | }
59 |
60 | [Fact]
61 | public void ExceptionIsNotCollectedAfterTryComplete()
62 | {
63 | var dc = new DiagnosticContext(Some.Logger());
64 | var collector = dc.BeginCollection();
65 | collector.TryComplete(out _, out _);
66 | dc.SetException(new Exception(Some.String("after collect")));
67 |
68 | var tryComplete2 = collector.TryComplete(out _, out var collectedException2);
69 |
70 | Assert.False(tryComplete2);
71 | Assert.Null(collectedException2);
72 | }
73 |
74 | [Fact]
75 | public void ExceptionIsNotCollectedAfterDispose()
76 | {
77 | var dc = new DiagnosticContext(Some.Logger());
78 | var collector = dc.BeginCollection();
79 | collector.Dispose();
80 |
81 | dc.SetException(new Exception("after dispose"));
82 |
83 | var tryComplete = collector.TryComplete(out _, out var collectedException);
84 |
85 | Assert.True(tryComplete);
86 | Assert.Null(collectedException);
87 | }
88 |
89 | [Fact]
90 | public void ExistingPropertiesCanBeUpdated()
91 | {
92 | var dc = new DiagnosticContext(Some.Logger());
93 |
94 | var collector = dc.BeginCollection();
95 | dc.Set("name", 10);
96 | dc.Set("name", 20);
97 |
98 | Assert.True(collector.TryComplete(out var properties, out var exception));
99 | var prop = Assert.Single(properties!);
100 | var scalar = Assert.IsType(prop.Value);
101 | Assert.Equal(20, scalar.Value);
102 | Assert.Null(exception);
103 | }
104 |
105 | [Fact]
106 | public void ExistingExceptionCanBeUpdated()
107 | {
108 | var dc = new DiagnosticContext(Some.Logger());
109 | var collector = dc.BeginCollection();
110 |
111 | dc.SetException(new Exception("ex1"));
112 | dc.SetException(new Exception("ex2"));
113 |
114 | Assert.True(collector.TryComplete(out _, out var collectedException));
115 | Assert.Equal("ex2", collectedException!.Message);
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/test/Serilog.Extensions.Hosting.Tests/LoggerSettingsConfigurationExtensionsTests.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Microsoft.Extensions.DependencyInjection;
3 | using Serilog.Core;
4 | using Serilog.Events;
5 | using Serilog.Extensions.Hosting.Tests.Support;
6 | using Xunit;
7 |
8 | namespace Serilog.Extensions.Hosting.Tests;
9 |
10 | public class LoggerSettingsConfigurationExtensionsTests
11 | {
12 | [Fact]
13 | public void SinksAreInjectedFromTheServiceProvider()
14 | {
15 | var emittedEvents = new List();
16 |
17 | var serviceCollection = new ServiceCollection();
18 | serviceCollection.AddSingleton(new ListSink(emittedEvents));
19 | using var services = serviceCollection.BuildServiceProvider();
20 |
21 | using var logger = new LoggerConfiguration()
22 | .ReadFrom.Services(services)
23 | .CreateLogger();
24 |
25 | logger.Information("Hello, world!");
26 |
27 | var evt = Assert.Single(emittedEvents);
28 | Assert.Equal("Hello, world!", evt!.MessageTemplate.Text);
29 | }
30 | }
--------------------------------------------------------------------------------
/test/Serilog.Extensions.Hosting.Tests/ReloadableLoggerTests.cs:
--------------------------------------------------------------------------------
1 | using Serilog.Core;
2 | using Serilog.Events;
3 | using Serilog.Extensions.Hosting.Tests.Support;
4 | using Xunit;
5 |
6 | namespace Serilog.Extensions.Hosting.Tests;
7 |
8 | public class ReloadableLoggerTests
9 | {
10 | [Fact]
11 | public void AFrozenLoggerYieldsSerilogLoggers()
12 | {
13 | var logger = new ReloadableLogger(new LoggerConfiguration().CreateLogger());
14 | var contextual = logger.ForContext();
15 |
16 | var nested = contextual.ForContext("test", "test");
17 | Assert.IsNotType(nested);
18 |
19 | logger.Freeze();
20 |
21 | nested = contextual.ForContext("test", "test");
22 | Assert.IsType(nested);
23 | }
24 |
25 | [Fact]
26 | public void CachingReloadableLoggerRemainsUsableAfterFreezing()
27 | {
28 | var logger = new LoggerConfiguration().CreateBootstrapLogger();
29 | var contextual = logger.ForContext();
30 | contextual.Information("First");
31 | logger.Reload(c => c);
32 | logger.Freeze();
33 | contextual.Information("Second");
34 | contextual.Information("Third");
35 | contextual.Information("Fourth"); // No crash :-)
36 | }
37 |
38 | [Fact]
39 | public void ReloadableLoggerRespectsMinimumLevelOverrides()
40 | {
41 | var emittedEvents = new List();
42 | var logger = new LoggerConfiguration()
43 | .MinimumLevel.Override("Test", LogEventLevel.Warning)
44 | .WriteTo.Sink(new ListSink(emittedEvents))
45 | .CreateBootstrapLogger();
46 |
47 | var limited = logger
48 | .ForContext("X", 1)
49 | .ForContext(Constants.SourceContextPropertyName, "Test.Stuff");
50 |
51 | var notLimited = logger.ForContext();
52 |
53 | foreach (var context in new[] { limited, notLimited })
54 | {
55 | // Suppressed by both sinks
56 | context.Debug("First");
57 |
58 | // Suppressed by the limited logger
59 | context.Information("Second");
60 |
61 | // Emitted by both loggers
62 | context.Warning("Third");
63 | }
64 |
65 | Assert.Equal(3, emittedEvents.Count);
66 | Assert.Equal(2, emittedEvents.Count(le => le.Level == LogEventLevel.Warning));
67 | }
68 |
69 | [Fact]
70 | public void ReloadableLoggersRecordEnrichment()
71 | {
72 | var emittedEvents = new List();
73 |
74 | var logger = new LoggerConfiguration()
75 | .WriteTo.Sink(new ListSink(emittedEvents))
76 | .CreateBootstrapLogger();
77 |
78 | var outer = logger
79 | .ForContext("A", new object());
80 | var inner = outer.ForContext("B", "test");
81 |
82 | inner.Information("First");
83 |
84 | logger.Reload(lc => lc.WriteTo.Sink(new ListSink(emittedEvents)));
85 |
86 | inner.Information("Second");
87 |
88 | logger.Freeze();
89 |
90 | inner.Information("Third");
91 |
92 | outer.ForContext("B", "test").Information("Fourth");
93 |
94 | logger.ForContext("A", new object())
95 | .ForContext("B", "test")
96 | .Information("Fifth");
97 |
98 | Assert.Equal(5, emittedEvents.Count);
99 | Assert.All(emittedEvents, e => Assert.Equal(2, e.Properties.Count));
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/test/Serilog.Extensions.Hosting.Tests/Serilog.Extensions.Hosting.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 | net4.8;net6.0;net8.0;net9.0
7 | false
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/test/Serilog.Extensions.Hosting.Tests/SerilogHostBuilderExtensionsTests.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Configuration;
2 | using Microsoft.Extensions.DependencyInjection;
3 | using Microsoft.Extensions.Hosting;
4 | using Microsoft.Extensions.Logging;
5 | using Xunit;
6 |
7 | namespace Serilog.Extensions.Hosting.Tests;
8 |
9 | public class SerilogHostBuilderExtensionsTests
10 | {
11 | [Fact]
12 | public void ServicesAreRegisteredWhenCallingUseSerilog()
13 | {
14 | // Arrange
15 | var collection = new ServiceCollection();
16 | IHostBuilder builder = new FakeHostBuilder(collection);
17 |
18 | // Act
19 | builder.UseSerilog();
20 |
21 | // Assert
22 | IServiceProvider provider = collection.BuildServiceProvider();
23 | provider.GetRequiredService();
24 | provider.GetRequiredService();
25 | }
26 |
27 | [Fact]
28 | public void ServicesAreRegisteredWhenCallingUseSerilogWithLogger()
29 | {
30 | // Arrange
31 | var collection = new ServiceCollection();
32 | IHostBuilder builder = new FakeHostBuilder(collection);
33 | ILogger logger = new LoggerConfiguration().CreateLogger();
34 |
35 | // Act
36 | builder.UseSerilog(logger);
37 |
38 | // Assert
39 | IServiceProvider provider = collection.BuildServiceProvider();
40 | provider.GetRequiredService();
41 | provider.GetRequiredService();
42 | provider.GetRequiredService();
43 | }
44 |
45 | [Fact]
46 | public void ServicesAreRegisteredWhenCallingUseSerilogWithConfigureDelegate()
47 | {
48 | // Arrange
49 | var collection = new ServiceCollection();
50 | IHostBuilder builder = new FakeHostBuilder(collection);
51 |
52 | // Act
53 | builder.UseSerilog((_, _) => { });
54 |
55 | // Assert
56 | IServiceProvider provider = collection.BuildServiceProvider();
57 | provider.GetRequiredService();
58 | provider.GetRequiredService();
59 | provider.GetRequiredService();
60 | }
61 |
62 | class FakeHostBuilder : IHostBuilder
63 | {
64 | readonly IServiceCollection _collection;
65 |
66 | public FakeHostBuilder(IServiceCollection collection) => _collection = collection;
67 |
68 | public IHostBuilder ConfigureHostConfiguration(Action configureDelegate)
69 | {
70 | throw new NotImplementedException();
71 | }
72 |
73 | public IHostBuilder ConfigureAppConfiguration(Action configureDelegate)
74 | {
75 | throw new NotImplementedException();
76 | }
77 |
78 | public IHostBuilder ConfigureServices(Action configureDelegate)
79 | {
80 | configureDelegate(null!, _collection);
81 | return this;
82 | }
83 |
84 | public IHostBuilder UseServiceProviderFactory(IServiceProviderFactory factory)
85 | where TContainerBuilder: notnull
86 | {
87 | throw new NotImplementedException();
88 | }
89 |
90 | public IHostBuilder UseServiceProviderFactory(Func> factory)
91 | where TContainerBuilder: notnull
92 | {
93 | throw new NotImplementedException();
94 | }
95 |
96 | public IHostBuilder ConfigureContainer(Action configureDelegate)
97 | {
98 | throw new NotImplementedException();
99 | }
100 |
101 | public IHost Build()
102 | {
103 | throw new NotImplementedException();
104 | }
105 |
106 | public IDictionary