Skip to content

Commit b7985ec

Browse files
authored
Merge pull request #1 from serilog/dev
1.0.0 Release
2 parents a3f48e5 + 29ef3d6 commit b7985ec

File tree

78 files changed

+24349
-2
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

78 files changed

+24349
-2
lines changed

.gitattributes

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Auto detect text files and perform LF normalization
2+
3+
* text=auto

Build.ps1

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
echo "build: Build started"
2+
3+
Push-Location $PSScriptRoot
4+
5+
if(Test-Path .\artifacts) {
6+
echo "build: Cleaning .\artifacts"
7+
Remove-Item .\artifacts -Force -Recurse
8+
}
9+
10+
& dotnet restore --no-cache
11+
12+
$branch = @{ $true = $env:APPVEYOR_REPO_BRANCH; $false = $(git symbolic-ref --short -q HEAD) }[$env:APPVEYOR_REPO_BRANCH -ne $NULL];
13+
$revision = @{ $true = "{0:00000}" -f [convert]::ToInt32("0" + $env:APPVEYOR_BUILD_NUMBER, 10); $false = "local" }[$env:APPVEYOR_BUILD_NUMBER -ne $NULL];
14+
$suffix = @{ $true = ""; $false = "$($branch.Substring(0, [math]::Min(10,$branch.Length)))-$revision"}[$branch -eq "master" -and $revision -ne "local"]
15+
16+
echo "build: Version suffix is $suffix"
17+
18+
foreach ($src in ls src/*) {
19+
Push-Location $src
20+
21+
echo "build: Packaging project in $src"
22+
23+
& dotnet pack -c Release -o ..\..\artifacts --version-suffix=$suffix
24+
if($LASTEXITCODE -ne 0) { exit 1 }
25+
26+
Pop-Location
27+
}
28+
29+
foreach ($test in ls test/*.PerformanceTests) {
30+
Push-Location $test
31+
32+
echo "build: Building performance test project in $test"
33+
34+
& dotnet build -c Release
35+
if($LASTEXITCODE -ne 0) { exit 2 }
36+
37+
Pop-Location
38+
}
39+
40+
foreach ($test in ls test/*.Tests) {
41+
Push-Location $test
42+
43+
echo "build: Testing project in $test"
44+
45+
& dotnet test -c Release
46+
if($LASTEXITCODE -ne 0) { exit 3 }
47+
48+
Pop-Location
49+
}
50+
51+
Pop-Location

README.md

Lines changed: 169 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,169 @@
1-
# serilog-extensions-logging-file
2-
Add file logging to ASP.NET Core apps in one line of code.
1+
# Serilog.Extensions.Logging.File [![NuGet Pre Release](https://img.shields.io/nuget/vpre/Serilog.Extensions.Logging.File.svg)](https://nuget.org/packages/Serilog.Extensions.Logging.File) [![Join the chat at https://gitter.im/serilog/serilog](https://img.shields.io/gitter/room/serilog/serilog.svg)](https://gitter.im/serilog/serilog) [![Build status](https://ci.appveyor.com/api/projects/status/rdff6bp9oeqfxif7?svg=true)](https://ci.appveyor.com/project/serilog/serilog-extensions-logging-file)
2+
3+
This package makes it a one-liner - `loggerFactory.AddFile()` - to configure top-quality file logging for ASP.NET Core apps.
4+
5+
* Text or JSON file output
6+
* Files roll over on date; capped file size
7+
* Request ids and event ids included with each message
8+
* Writes are performed on a background thread
9+
* Files are periodically flushed to disk (required for Azure App Service log collection)
10+
* Fast, stable, battle-proven logging code courtesy of [Serilog](https://serilog.net)
11+
12+
You can get started quickly with this package, and later migrate to the full Serilog API if you need more sophisticated log file configuration.
13+
14+
### Getting started
15+
16+
**1.** Add [the NuGet package](https://nuget.org/packages/serilog.extensions.logging.file) to the `"dependencies"` section of your `project.json` file:
17+
18+
```json
19+
"dependencies": {
20+
"Serilog.Extensions.Logging.File": "1.0.0"
21+
}
22+
```
23+
24+
**2.** In your `Startup` class's `Configure()` method, call `AddFile()` on the provided `loggerFactory`.
25+
26+
```csharp
27+
public void Configure(IApplicationBuilder app,
28+
IHostingEnvironment env,
29+
ILoggerFactory loggerFactory)
30+
{
31+
loggerFactory.AddFile("Logs/myapp-{Date}.txt");
32+
```
33+
34+
**Done!** The framework will inject `ILogger` instances into controllers and other classes:
35+
36+
```csharp
37+
class HomeController : Controller
38+
{
39+
readonly ILogger<HomeController> _log;
40+
41+
public HomeController(ILogger<HomeController> log)
42+
{
43+
_log = log;
44+
}
45+
46+
public IActionResult Index()
47+
{
48+
_log.LogInformation("Hello, world!");
49+
}
50+
}
51+
```
52+
53+
The events will appear in the log file:
54+
55+
```
56+
2016-10-18T11:14:11.0881912+10:00 0HKVMUG8EMJO9 [INF] Hello, world! (f83bcf75)
57+
```
58+
59+
### File format
60+
61+
By default, the file will be written in plain text. The fields in the log file are:
62+
63+
| Field | Description | Format | Example |
64+
| ----- | ----------- | ------ | ------- |
65+
| **Timestamp** | The time the event occurred. | ISO-8601 with offset | `2016-10-18T11:14:11.0881912+10:00` |
66+
| **Request id** | Uniquely identifies all messages raised during a single web request. | Alphanumeric | `0HKVMUG8EMJO9` |
67+
| **Level** | The log level assigned to the event. | Three-character code in brackets | `[INF]` |
68+
| **Message** | The log message associated with the event. | Free text | `Hello, world!` |
69+
| **Event id** | Identifies messages generated from the same format string/message template. | 32-bit hexadecimal, in parentheses | `(f83bcf75)` |
70+
| **Exception** | Exception associated with the event. | `Exception.ToString()` format (not shown) | `System.DivideByZeroException: Attempt to divide by zero\r\n\ at...` |
71+
72+
To record events in newline-separated JSON instead, specify `isJson: true` when configuring the logger:
73+
74+
```csharp
75+
loggerFactory.AddFile("Logs/myapp-{Date}.txt", isJson: true);
76+
```
77+
78+
This will produce a log file with lines like:
79+
80+
```json
81+
{"@t":"2016-06-07T03:44:57.8532799Z","@m":"Hello, world!","@i":"f83bcf75","RequestId":"0HKVMUG8EMJO9"}
82+
```
83+
84+
The JSON document includes all properties associated with the event, not just those present in the message. This makes JSON formatted logs a better choice for offline analysis in many cases.
85+
86+
### Rolling
87+
88+
The filename provided to `AddFile()` should include the `{Date}` placeholder, which will be replaced with the date of the events contained in the file. Filenames use the `yyyyMMdd` date format so that files can be ordered using a lexicographic sort:
89+
90+
```
91+
log-20160631.txt
92+
log-20160701.txt
93+
log-20160702.txt
94+
```
95+
96+
To prevent outages due to disk space exhaustion, each file is capped to 1 GB in size. If the file size is exceeded, events will be dropped until the next roll point.
97+
98+
### Message templates and event ids
99+
100+
The provider supports the templated log messages used by _Microsoft.Extensions.Logging_. By writing events with format strings or [message templates](https://messagetemplates.org), the provider can infer which messages came from the same logging statement.
101+
102+
This means that although the text of two messages may be different, their **event id** fields will match, as shown by the two "view" logging statements below:
103+
104+
```
105+
2016-10-18T11:14:26.2544709+10:00 0HKVMUG8EMJO9 [INF] Running view at "/Views/Home/About.cshtml". (9707eebe)
106+
2016-10-18T11:14:11.0881912+10:00 0HKVMUG8EMJO9 [INF] Hello, world! (f83bcf75)
107+
2016-10-18T11:14:26.2544709+10:00 0HKVMUG8EMJO9 [INF] Running view at "/Views/Home/Index.cshtml". (9707eebe)
108+
```
109+
110+
Each log message describing view rendering is tagged with `(9707eebe)`, while the "hello" log message is given `(f83bcf75)`. This makes it easy to search the log for messages describing the same kind of event.
111+
112+
### Additional configuration
113+
114+
The `AddFile()` method exposes some basic options for controlling the connection and log volume.
115+
116+
| Parameter | Description | Example value |
117+
| --------- | ----------- | ------------- |
118+
| `pathFormat` | Filname to write. The filename may include `{Date}` to specify how the date portion of the filename is calculated. May include environment variables.| `Logs/log-{Date}.txt` |
119+
| `minimumLevel` | The level below which events will be suppressed (the default is `LogLevel.Information`). | `LogLevel.Debug` |
120+
| `levelOverrides` | A dictionary mapping logger name prefixes to minimum logging levels. | |
121+
| `isJson` | If true, the log file will be written in JSON format. | `true` |
122+
| `fileSizeLimitBytes` | The maximum size, in bytes, to which any single log file will be allowed to grow. For unrestricted growth, pass`null`. The default is 1 GiB. | `1024 * 1024 * 1024` |
123+
| `retainedFileCountLimit` | The maximum number of log files that will be retained, including the current log file. For unlimited retention, pass `null`. The default is `31`. | `31` |
124+
125+
### `appsettings.json` configuration
126+
127+
The file path and other settings can be read from JSON configuration if desired.
128+
129+
In `appsettings.json` add a `"Logging"` property:
130+
131+
```json
132+
{
133+
"Logging": {
134+
"PathFormat": "Logs/log-{Date}.txt",
135+
"LogLevel": {
136+
"Default": "Debug",
137+
"Microsoft": "Information"
138+
}
139+
}
140+
}
141+
```
142+
143+
And then pass the configuration section to the `AddFile()` method:
144+
145+
```csharp
146+
loggerFactory.AddFile(Configuration.GetSection("Logging"));
147+
```
148+
149+
In addition to the properties shown above, the `"Logging"` configuration supports:
150+
151+
| Property | Description | Example |
152+
| -------- | ----------- | ------- |
153+
| `Json` | If `true`, the log file will be written in JSON format. | `true` |
154+
| `FileSizeLimitBytes` | The maximum size, in bytes, to which any single log file will be allowed to grow. For unrestricted growth, pass`null`. The default is 1 GiB. | `1024 * 1024 * 1024` |
155+
| `RetainedFileCountLimit` | The maximum number of log files that will be retained, including the current log file. For unlimited retention, pass `null`. The default is `31`. | `31` |
156+
157+
### Using the full Serilog API
158+
159+
This package is opinionated, providing the most common/recommended options supported by Serilog. For more sophisticated configuration, using Serilog directly is recommened. See the instructions in [Serilog.Extensions.Logging](https://github.com/serilog/serilog-extensions-logging) to get started.
160+
161+
The following packages are used to provide `AddFile()`:
162+
163+
* [Serilog](https://github.com/serilog/serilog) - the core logging pipeline
164+
* [Serilog.Sinks.RollingFile](https://github.com/serilog/serilog-sinks-rollingfile) - rolling file output
165+
* [Serilog.Formatting.Compact](https://github.com/serilog/serilog-formatting-compact) - JSON event formatting
166+
* [Serilog.Extensions.Logging](https://github.com/serilog/serilog-extensions-logging) - ASP.NET Core integration
167+
* [Serilog.Sinks.Async](https://github.com/serilog/serilog-sinks-async) - async wrapper to perform log writes on a background thread
168+
169+
If you decide to switch to the full Serilog API and need help, please drop into the [Gitter channel](https://gitter.im/serilog/serilog) or post your question on [Stack Overflow](http://stackoverflow.com/questions/tagged/serilog).

appveyor.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
version: '{build}'
2+
skip_tags: true
3+
image: Visual Studio 2015
4+
configuration: Release
5+
install:
6+
- ps: mkdir -Force ".\build\" | Out-Null
7+
- ps: Invoke-WebRequest "https://raw.githubusercontent.com/dotnet/cli/rel/1.0.0-preview2/scripts/obtain/dotnet-install.ps1" -OutFile ".\build\installcli.ps1"
8+
- ps: $env:DOTNET_INSTALL_DIR = "$pwd\.dotnetcli"
9+
- ps: '& .\build\installcli.ps1 -InstallDir "$env:DOTNET_INSTALL_DIR" -NoPath -Version 1.0.0-preview2-003121'
10+
- ps: $env:Path = "$env:DOTNET_INSTALL_DIR;$env:Path"
11+
build_script:
12+
- ps: ./Build.ps1
13+
test: off
14+
artifacts:
15+
- path: artifacts/Serilog.*.nupkg
16+
deploy:
17+
- provider: NuGet
18+
api_key:
19+
secure: nvZ/z+pMS91b3kG4DgfES5AcmwwGoBYQxr9kp4XiJHj25SAlgdIxFx++1N0lFH2x
20+
skip_symbols: true
21+
on:
22+
branch: /^(master|dev)$/
23+
- provider: GitHub
24+
auth_token:
25+
secure: p4LpVhBKxGS5WqucHxFQ5c7C8cP74kbNB0Z8k9Oxx/PMaDQ1+ibmoexNqVU5ZlmX
26+
artifact: /Serilog.*\.nupkg/
27+
tag: v$(appveyor_build_version)
28+
on:
29+
branch: master

assets/Serilog.snk

596 Bytes
Binary file not shown.

example/WebApplication/.bowerrc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"directory": "wwwroot/lib"
3+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Threading.Tasks;
5+
using Microsoft.AspNetCore.Mvc;
6+
using Microsoft.Extensions.Logging;
7+
8+
namespace WebApplication.Controllers
9+
{
10+
public class HomeController : Controller
11+
{
12+
readonly ILogger<HomeController> _log;
13+
14+
public HomeController(ILogger<HomeController> log)
15+
{
16+
_log = log;
17+
}
18+
19+
public IActionResult Index()
20+
{
21+
_log.LogInformation("Hello, world!");
22+
23+
return View();
24+
}
25+
26+
public IActionResult About()
27+
{
28+
ViewData["Message"] = "Your application description page.";
29+
30+
return View();
31+
}
32+
33+
public IActionResult Contact()
34+
{
35+
ViewData["Message"] = "Your contact page.";
36+
37+
return View();
38+
}
39+
40+
public IActionResult Error()
41+
{
42+
return View();
43+
}
44+
}
45+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2016-10-18T13:03:50.6053012+10:00 0HKVN0DHETANV [INF] Request starting HTTP/1.1 GET http://localhost:58951/ (e5be5b71)
2+
2016-10-18T13:03:50.6057982+10:00 0HKVN0DHETAO0 [INF] Request starting HTTP/1.1 DEBUG http://localhost:58951/ 0 (e5be5b71)
3+
2016-10-18T13:03:50.7413643+10:00 0HKVN0DHETAO0 [INF] Request finished in 148.0663ms 200 (15c52c40)
4+
2016-10-18T13:03:51.1853627+10:00 0HKVN0DHETANV [INF] Executing action method "WebApplication.Controllers.HomeController.Index (WebApplication)" with arguments (null) - ModelState is Valid (ba7f4ac2)
5+
2016-10-18T13:03:51.1968635+10:00 0HKVN0DHETANV [INF] Hello, world! (f83bcf75)
6+
2016-10-18T13:04:18.3003860+10:00 0HKVN0DHETANV [INF] Executing ViewResult, running view at path "/Views/Home/Index.cshtml". (9707eebe)
7+
2016-10-18T13:04:18.4170672+10:00 0HKVN0DHETANV [INF] User profile is available. Using '"C:\Users\nblumhardt\AppData\Local\ASP.NET\DataProtection-Keys"' as key repository and Windows DPAPI to encrypt keys at rest. (7ac5e29c)

example/WebApplication/Program.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
using System.Threading.Tasks;
6+
using Microsoft.AspNetCore.Hosting;
7+
8+
namespace WebApplication
9+
{
10+
public class Program
11+
{
12+
public static void Main(string[] args)
13+
{
14+
var host = new WebHostBuilder()
15+
.UseKestrel()
16+
.UseContentRoot(Directory.GetCurrentDirectory())
17+
.UseIISIntegration()
18+
.UseStartup<Startup>()
19+
.Build();
20+
21+
host.Run();
22+
}
23+
}
24+
}

0 commit comments

Comments
 (0)