Skip to content

Commit a1eb2ec

Browse files
authored
Version 4.0.0 (#117)
1 parent 28d6952 commit a1eb2ec

24 files changed

+607
-613
lines changed

CHANGES.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Changes
22

3+
### 4.0.0 07/17/2024
4+
- Updated to Serilog 4.0.0 and implemented support for Serilog native IBatchedLogEventSink. All usage of AzureBlobStorage is now batched on a default 2 second emit interval. The first log event is written immediately.
5+
- Implemented support for including the log event level (Information, Warning, etc) in the file name template. This is done by including the `Level` property in the template. For example, `Log-{yyyy}-{MM}-{dd}-{Level}.txt` will create files like `Log-2024-07-17-Information.txt`.
6+
- Fixed support for deleting old files by implementing Regex matching instead of DateTime parsing in the delete routine.
7+
- Added console app sample to demonstrate the new features.
8+
- This major update may require you to alter your configuration settings where you define usage of this sink.
9+
310
### 3.3.2 07/13/2024
411
- Updated Azure.Identity to fix CVE-2024-35255. The next release will be a major version update to adopt Serilog 4.0.0 and IBatchedLogEventSink.
512

README.md

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Serilog.Sinks.AzureBlobStorage
22

3-
![Build status](https://dev.azure.com/cloudscope/Open%20Source/_apis/build/status/SeriLog-AzureBlobSink%20release "Build status")
3+
![Build status](https://dev.azure.com/cloudscope/Open%20Source/_apis/build/status/SeriLog-AzureBlobSink%20release 'Build status')
44
[![NuGet Badge](https://buildstats.info/nuget/Serilog.Sinks.AzureBlobStorage)](https://www.nuget.org/packages/Serilog.Sinks.AzureBlobStorage/)
55

66
Writes to a file in [Windows Azure Blob Storage](https://azure.microsoft.com/en-us/services/storage/blobs/).
@@ -13,15 +13,15 @@ The AzureBlobStorage sink appends data to the blob in text format. Here's a samp
1313
[2018-10-17 23:03:56 INF] Hello World!
1414
```
1515

16-
**Package** - [Serilog.Sinks.AzureBlobStorage](http://nuget.org/packages/serilog.sinks.azureblobstorage) | **Platforms** - .Net Standard 2.0
16+
**Package** - [Serilog.Sinks.AzureBlobStorage](http://nuget.org/packages/serilog.sinks.azureblobstorage) | **Platforms** - netstandard2.0; netstandard2.1; net6.0; net8.0
1717

1818
**Usage**
1919

2020
```csharp
21-
var cloudAccount = CloudStorageAccount.Parse("ConnectionString");
21+
var azureConnectionString = "my connection string";
2222

2323
var log = new LoggerConfiguration()
24-
.WriteTo.AzureBlobStorage(cloudAccount)
24+
.WriteTo.AzureBlobStorage(connectionString: azureConnectionString)
2525
.CreateLogger();
2626
```
2727

@@ -98,6 +98,13 @@ As of version 2.0.0, the values are not required to appear in descending order,
9898
2019/06/20/2019-06-20_14:40.txt
9999
```
100100

101+
#### Other substitutions in the file name.
102+
103+
- You can add the LogEventLevel to the file name by using the {Level} descriptor. For example, use this file name template: {Level}.txt.
104+
- If you push properties into Serilog, you can use those within your file name template. Caution! If you do this, you must do it consistently. For more information, see the 'Multi-tenant support' example below.
105+
106+
All of these substitutions can be used in together and also with the date formats.
107+
101108
#### Maximum file size
102109

103110
You can limit the size of each file created as of version 2.0.0. There is a constructor parameter called `blobSizeLimitBytes`. By
@@ -110,20 +117,20 @@ be deleted every time a new file is created in order to stay within this limit.
110117

111118
#### Batch posting example
112119

113-
By default, whenever there is a new event to post, the Azure Blob Storage sink will send it to Azure storage. For cost-management or performance reasons, you can
114-
choose to "batch" the posting of new log events.
120+
As of version 4.0, the AzureBlobStorageSink uses batching exclusively for posting events, and uses Serilog 4.0's native batching features. There is no configuration
121+
required to take advantage of this feature. Batches are emitted every 2 seconds, if events are waiting. A single batch can include up to 1000 events.
115122

116-
You should create the sink by calling the [AzureBatchingBlobStorageSink](https://github.com/chriswill/serilog-sinks-azureblobstorage/blob/master/src/Serilog.Sinks.AzureBlobStorage/Sinks/AzureBlobStorage/AzureBatchingBlobStorageSink.cs) class, which inherits from PeriodicBatchingSink.
123+
If you want to control the batch posting limit and the period, you can do so by using the `batchPostingLimit` and `period` parameters.
117124

118125
An example configuration is:
119126

120127
```csharp
121-
.WriteTo.AzureBlobStorage(blobServiceClient, Serilog.Events.LogEventLevel.Information, writeInBatches:true, period:TimeSpan.FromSeconds(15), batchPostingLimit:10)
128+
.WriteTo.AzureBlobStorage(blobServiceClient, Serilog.Events.LogEventLevel.Information, period:TimeSpan.FromSeconds(30), batchPostingLimit:50)
122129
```
123130

124-
This configuration would post a new batch of events every 15 seconds, unless there were 10 or more events to post, in which case they would post before the time limit.
131+
This configuration would post a new batch of events every 30 seconds, unless there were 50 or more events to post, in which case they would post before the time limit.
125132

126-
To specify batch posting using configuration, configure use need to set these mandatory values:
133+
To specify batch posting using appsettings configuration, configure these values:
127134

128135
```json
129136
"WriteTo": [
@@ -133,9 +140,8 @@ To specify batch posting using configuration, configure use need to set these ma
133140
"connectionString": "",
134141
"storageContainerName": "",
135142
"storageFileName": "",
136-
"writeInBatches": "true", // mandatory
137-
"period": "0.00:00:30", // mandatory sets the period to 30 secs
138-
"batchPostingLimit": "50", // optional
143+
"period": "00:00:30", // optional sets the period to 30 secs
144+
"batchPostingLimit": "50", // optional, sets the max batch limit to 50
139145
}
140146
}
141147
]
@@ -149,8 +155,8 @@ To configure, create a storage filename that includes a tenant id property.
149155

150156
```json
151157
loggerConfiguration.WriteTo.
152-
AzureBlobStorage("blobconnectionstring",
153-
LogEventLevel.Information, "Containername", storageFileName: "/{TenantId}/{yyyy}/{MM}/log{yyyy}{MM}{dd}.txt",
158+
AzureBlobStorage("blobconnectionstring",
159+
LogEventLevel.Information, "Containername", storageFileName: "/{TenantId}/{yyyy}/{MM}/log{yyyy}{MM}{dd}.txt",
154160
writeInBatches: true, period: TimeSpan.FromSeconds(15), batchPostingLimit: 100);
155161
```
156162

azure-pipelines.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ trigger:
55
- '*'
66

77
pool:
8-
vmImage: 'windows-2019'
8+
vmImage: 'windows-latest'
99

1010
variables:
1111
buildConfiguration: 'Release'
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using Microsoft.Extensions.Hosting;
2+
using Microsoft.Extensions.Logging;
3+
4+
namespace SampleConsoleApp
5+
{
6+
public class PrintTimeService : BackgroundService
7+
{
8+
private readonly ILogger<PrintTimeService> logger;
9+
10+
public PrintTimeService(ILogger<PrintTimeService> logger)
11+
{
12+
this.logger = logger;
13+
}
14+
15+
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
16+
{
17+
while (!stoppingToken.IsCancellationRequested)
18+
{
19+
logger.LogInformation("The current time is: {CurrentTime}", DateTimeOffset.UtcNow);
20+
await Task.Delay(TimeSpan.FromSeconds(5), stoppingToken);
21+
}
22+
}
23+
}
24+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
using Microsoft.Extensions.DependencyInjection;
2+
using Microsoft.Extensions.Hosting;
3+
using Serilog;
4+
using Serilog.Events;
5+
6+
namespace SampleConsoleApp
7+
{
8+
internal class Program
9+
{
10+
private const string OutputTemplate = "{Timestamp:HH:mm:ss.fff} [{Level:u1}] {Message:lj}{NewLine}{Exception}";
11+
12+
static async Task<int> Main(string[] args)
13+
{
14+
Log.Logger = new LoggerConfiguration()
15+
.MinimumLevel.Verbose()
16+
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
17+
.Enrich.FromLogContext()
18+
.WriteTo.Console(outputTemplate: OutputTemplate)
19+
.CreateBootstrapLogger();
20+
21+
try
22+
{
23+
Log.Information("Starting Console Host");
24+
25+
var app = Host
26+
.CreateDefaultBuilder(args)
27+
.ConfigureServices(services => services.AddHostedService<PrintTimeService>())
28+
.UseSerilog((context, services, configuration) => configuration
29+
.ReadFrom.Configuration(context.Configuration)
30+
)
31+
.Build();
32+
33+
Serilog.Debugging.SelfLog.Enable(Console.Error);
34+
35+
await app.RunAsync();
36+
37+
return 0;
38+
}
39+
catch (Exception ex)
40+
{
41+
Log.Fatal(ex, "Host terminated unexpectedly");
42+
return 1;
43+
}
44+
finally
45+
{
46+
await Log.CloseAndFlushAsync();
47+
}
48+
49+
}
50+
}
51+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net8.0</TargetFramework>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
</PropertyGroup>
9+
10+
<ItemGroup>
11+
<None Remove="appsettings.json" />
12+
</ItemGroup>
13+
14+
<ItemGroup>
15+
<Content Include="appsettings.json">
16+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
17+
</Content>
18+
</ItemGroup>
19+
20+
<ItemGroup>
21+
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
22+
<PackageReference Include="Serilog.Extensions.Hosting" Version="8.0.0" />
23+
<PackageReference Include="Serilog.Settings.Configuration" Version="8.0.2" />
24+
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
25+
</ItemGroup>
26+
27+
<ItemGroup>
28+
<ProjectReference Include="..\..\src\Serilog.Sinks.AzureBlobStorage\Serilog.Sinks.AzureBlobStorage.csproj" />
29+
</ItemGroup>
30+
31+
</Project>
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"Serilog": {
3+
"Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.AzureBlobStorage" ],
4+
"MinimumLevel": {
5+
"Default": "Verbose"
6+
},
7+
"WriteTo": [
8+
{
9+
"Name": "Console",
10+
"Args": {
11+
"outputTemplate": "{Timestamp:HH:mm:ss.fff} [{Level:u1}] {Message:lj}{NewLine}{Exception}"
12+
}
13+
},
14+
{
15+
"Name": "AzureBlobStorage",
16+
"Args": {
17+
"connectionString": "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;QueueEndpoint=http://127.0.0.1:10001/devstoreaccount1;TableEndpoint=http://127.0.0.1:10002/devstoreaccount1;",
18+
"storageContainerName": "logs",
19+
"storageFileName": "{HH}-{mm}-{Level}-log.txt",
20+
"period": "00:01:30",
21+
"retainedBlobCountLimit": 4
22+
}
23+
}
24+
]
25+
},
26+
"AllowedHosts": "*"
27+
}

serilog-sinks-azureblobstorage.sln

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{BD6DDC9A-B
1616
EndProject
1717
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Serilog.Sinks.AzureBlobStorage.UnitTest", "tests\Serilog.Sinks.AzureBlobStorage.UnitTest\Serilog.Sinks.AzureBlobStorage.UnitTest.csproj", "{F94B805F-E056-4921-8EC2-0B0F4849BBE8}"
1818
EndProject
19+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{C34B192A-D0CB-4549-8F55-F0A4BFB683EE}"
20+
EndProject
21+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SampleConsoleApp", "samples\SampleConsoleApp\SampleConsoleApp.csproj", "{4C63B434-362A-485A-9539-0ABB57849436}"
22+
EndProject
1923
Global
2024
GlobalSection(SolutionConfigurationPlatforms) = preSolution
2125
Debug|Any CPU = Debug|Any CPU
@@ -30,12 +34,17 @@ Global
3034
{F94B805F-E056-4921-8EC2-0B0F4849BBE8}.Debug|Any CPU.Build.0 = Debug|Any CPU
3135
{F94B805F-E056-4921-8EC2-0B0F4849BBE8}.Release|Any CPU.ActiveCfg = Release|Any CPU
3236
{F94B805F-E056-4921-8EC2-0B0F4849BBE8}.Release|Any CPU.Build.0 = Release|Any CPU
37+
{4C63B434-362A-485A-9539-0ABB57849436}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
38+
{4C63B434-362A-485A-9539-0ABB57849436}.Debug|Any CPU.Build.0 = Debug|Any CPU
39+
{4C63B434-362A-485A-9539-0ABB57849436}.Release|Any CPU.ActiveCfg = Release|Any CPU
40+
{4C63B434-362A-485A-9539-0ABB57849436}.Release|Any CPU.Build.0 = Release|Any CPU
3341
EndGlobalSection
3442
GlobalSection(SolutionProperties) = preSolution
3543
HideSolutionNode = FALSE
3644
EndGlobalSection
3745
GlobalSection(NestedProjects) = preSolution
3846
{F94B805F-E056-4921-8EC2-0B0F4849BBE8} = {BD6DDC9A-B4A7-49E9-99F9-1EB7C462BF67}
47+
{4C63B434-362A-485A-9539-0ABB57849436} = {C34B192A-D0CB-4549-8F55-F0A4BFB683EE}
3948
EndGlobalSection
4049
GlobalSection(ExtensibilityGlobals) = postSolution
4150
SolutionGuid = {73E16F7E-6DF4-4355-BF3C-73DDBBA1867E}

0 commit comments

Comments
 (0)