Skip to content

Commit

Permalink
Merge pull request #161 from datalust/dev
Browse files Browse the repository at this point in the history
5.1.0 Release
  • Loading branch information
nblumhardt authored Nov 12, 2021
2 parents 796b34c + 76e9a9b commit 5d03588
Show file tree
Hide file tree
Showing 40 changed files with 895 additions and 531 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Serilog.Sinks.Seq [![Build status](https://ci.appveyor.com/api/projects/status/t7qdv68pej6inukl/branch/master?svg=true)](https://ci.appveyor.com/project/serilog/serilog-sinks-seq/branch/master) [![NuGet](https://img.shields.io/nuget/v/Serilog.Sinks.Seq.svg)](https://nuget.org/packages/serilog.sinks.seq) [![Join the chat at https://gitter.im/serilog/serilog](https://img.shields.io/gitter/room/serilog/serilog.svg)](https://gitter.im/serilog/serilog)
# Serilog.Sinks.Seq [![Build status](https://ci.appveyor.com/api/projects/status/uwkn795klja7u74f/branch/dev?svg=true)](https://ci.appveyor.com/project/datalust/serilog-sinks-seq/branch/dev) [![NuGet](https://img.shields.io/nuget/v/Serilog.Sinks.Seq.svg)](https://nuget.org/packages/serilog.sinks.seq) [![Join the chat at https://gitter.im/serilog/serilog](https://img.shields.io/gitter/room/serilog/serilog.svg)](https://gitter.im/serilog/serilog)

A Serilog sink that writes events to the [Seq](https://datalust.co/seq) structured log server. Supports .NET 4.5+, .NET Core, and platforms compatible with the [.NET Platform Standard](https://github.com/dotnet/corefx/blob/master/Documentation/architecture/net-platform-standard.md) 1.1 including Windows 8 & UWP, Windows Phone and Xamarin.

Expand Down
2 changes: 1 addition & 1 deletion appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ artifacts:
deploy:
- provider: NuGet
api_key:
secure: K6TcIFIyxBcDuZ5DL7bJC+fGwDo458q0SDh+ybLujGTddA/voxg2FMUtJQ7rTEbt
secure: cOwNnD1CeLHceEpQiS89arAbxzPLgQKnsffzu2KthmbTY6OL7rMXrkud6EBq4sOo
skip_symbols: true
on:
branch: /^(main|dev)$/
Expand Down
4 changes: 2 additions & 2 deletions global.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"sdk": {
"version": "5.0.202",
"rollForward": "latestPatch"
"version": "5.0.401",
"rollForward": "latestFeature"
}
}
5 changes: 2 additions & 3 deletions sample/Sample/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

namespace Sample
{
public class Program
public static class Program
{
public static void Main()
{
Expand All @@ -16,8 +16,7 @@ public static void Main()
Log.Logger = new LoggerConfiguration()
.MinimumLevel.ControlledBy(levelSwitch)
.WriteTo.Console()
.WriteTo.Seq("http://localhost:5341",
controlLevelSwitch: levelSwitch)
.WriteTo.Seq("http://localhost:5341", controlLevelSwitch: levelSwitch)
.CreateLogger();

Log.Information("Sample starting up");
Expand Down
21 changes: 4 additions & 17 deletions sample/Sample/Sample.csproj
Original file line number Diff line number Diff line change
@@ -1,35 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<Description>Sample Console Application</Description>
<Authors>nblumhardt</Authors>
<TargetFrameworks>netcoreapp3.1;net47</TargetFrameworks>
<AssemblyName>Sample</AssemblyName>
<TargetFrameworks>net4.8;net5.0</TargetFrameworks>
<OutputType>Exe</OutputType>
<PackageId>Sample</PackageId>
<GenerateAssemblyTitleAttribute>false</GenerateAssemblyTitleAttribute>
<GenerateAssemblyDescriptionAttribute>false</GenerateAssemblyDescriptionAttribute>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<GenerateAssemblyCopyrightAttribute>false</GenerateAssemblyCopyrightAttribute>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
</PropertyGroup>

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

<ItemGroup Condition=" '$(TargetFramework)' == 'net47' ">
<ItemGroup Condition=" '$(TargetFramework)' == 'net4.8' ">
<Reference Include="System.Net.Http" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Serilog.Sinks.Seq\Serilog.Sinks.Seq.csproj" />
</ItemGroup>

<ItemGroup>
<Folder Include="logs\" />
</ItemGroup>

</Project>
1 change: 1 addition & 0 deletions serilog-sinks-seq.sln.DotSettings
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/UserDictionary/Words/=aaaaa/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Backoff/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=delim/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=fdelim/@EntryIndexedValue">True</s:Boolean>
Expand Down
43 changes: 23 additions & 20 deletions src/Serilog.Sinks.Seq/SeqLoggerConfigurationExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
using Serilog.Sinks.Seq;
using System.Net.Http;
using Serilog.Sinks.PeriodicBatching;
using Serilog.Sinks.Seq.Batched;
using Serilog.Sinks.Seq.Audit;
using Serilog.Sinks.Seq.Http;

#if DURABLE
using Serilog.Sinks.Seq.Durable;
Expand All @@ -32,8 +34,12 @@ namespace Serilog
/// </summary>
public static class SeqLoggerConfigurationExtensions
{
const int DefaultBatchPostingLimit = 1000;
static readonly TimeSpan DefaultPeriod = TimeSpan.FromSeconds(2);
const int DefaultQueueSizeLimit = 100000;

/// <summary>
/// Adds a sink that writes log events to a <a href="https://getseq.net">Seq</a> server.
/// Write log events to a <a href="https://datalust.co/seq">Seq</a> server.
/// </summary>
/// <param name="loggerSinkConfiguration">The logger configuration.</param>
/// <param name="serverUrl">The base URL of the Seq server that log events will be written to.</param>
Expand Down Expand Up @@ -67,37 +73,35 @@ public static LoggerConfiguration Seq(
this LoggerSinkConfiguration loggerSinkConfiguration,
string serverUrl,
LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum,
int batchPostingLimit = SeqSink.DefaultBatchPostingLimit,
int batchPostingLimit = DefaultBatchPostingLimit,
TimeSpan? period = null,
string apiKey = null,
string bufferBaseFilename = null,
string? apiKey = null,
string? bufferBaseFilename = null,
long? bufferSizeLimitBytes = null,
long? eventBodyLimitBytes = 256*1024,
LoggingLevelSwitch controlLevelSwitch = null,
HttpMessageHandler messageHandler = null,
LoggingLevelSwitch? controlLevelSwitch = null,
HttpMessageHandler? messageHandler = null,
long? retainedInvalidPayloadsLimitBytes = null,
int queueSizeLimit = SeqSink.DefaultQueueSizeLimit)
int queueSizeLimit = DefaultQueueSizeLimit)
{
if (loggerSinkConfiguration == null) throw new ArgumentNullException(nameof(loggerSinkConfiguration));
if (serverUrl == null) throw new ArgumentNullException(nameof(serverUrl));
if (bufferSizeLimitBytes.HasValue && bufferSizeLimitBytes < 0)
if (bufferSizeLimitBytes is < 0)
throw new ArgumentOutOfRangeException(nameof(bufferSizeLimitBytes), "Negative value provided; buffer size limit must be non-negative.");
if (queueSizeLimit < 0)
throw new ArgumentOutOfRangeException(nameof(queueSizeLimit), "Queue size limit must be non-zero.");

var defaultedPeriod = period ?? SeqSink.DefaultPeriod;
var defaultedPeriod = period ?? DefaultPeriod;
var controlledSwitch = new ControlledLevelSwitch(controlLevelSwitch);

ILogEventSink sink;

if (bufferBaseFilename == null)
{
var batchedSink = new SeqSink(
serverUrl,
apiKey,
var batchedSink = new BatchedSeqSink(
new SeqIngestionApiClient(serverUrl, apiKey, messageHandler),
eventBodyLimitBytes,
controlledSwitch,
messageHandler);
controlledSwitch);

var options = new PeriodicBatchingSinkOptions
{
Expand Down Expand Up @@ -134,7 +138,7 @@ public static LoggerConfiguration Seq(
}

/// <summary>
/// Adds a sink that writes audit log events to a <a href="https://getseq.net">Seq</a> server. Auditing writes are
/// Write audit log events to a <a href="https://datalust.co/seq">Seq</a> server. Auditing writes are
/// synchronous and non-batched; any failures will propagate to the caller immediately as exceptions.
/// </summary>
/// <param name="loggerAuditSinkConfiguration">The logger configuration.</param>
Expand All @@ -149,15 +153,14 @@ public static LoggerConfiguration Seq(
this LoggerAuditSinkConfiguration loggerAuditSinkConfiguration,
string serverUrl,
LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum,
string apiKey = null,
HttpMessageHandler messageHandler = null)
string? apiKey = null,
HttpMessageHandler? messageHandler = null)
{
if (loggerAuditSinkConfiguration == null) throw new ArgumentNullException(nameof(loggerAuditSinkConfiguration));
if (serverUrl == null) throw new ArgumentNullException(nameof(serverUrl));

return loggerAuditSinkConfiguration.Sink(
new SeqAuditSink(serverUrl, apiKey, messageHandler),
restrictedToMinimumLevel);
var ingestionApi = new SeqIngestionApiClient(serverUrl, apiKey, messageHandler);
return loggerAuditSinkConfiguration.Sink(new SeqAuditSink(ingestionApi), restrictedToMinimumLevel);
}
}
}
16 changes: 9 additions & 7 deletions src/Serilog.Sinks.Seq/Serilog.Sinks.Seq.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

<PropertyGroup>
<Description>Serilog sink that writes to the Seq log server over HTTP/HTTPS.</Description>
<VersionPrefix>5.0.1</VersionPrefix>
<VersionPrefix>5.1.0</VersionPrefix>
<Authors>Serilog Contributors</Authors>
<Copyright>Copyright © Serilog Contributors</Copyright>
<TargetFrameworks>netstandard1.1;netstandard1.3;net45;netstandard2.0;netcoreapp3.1;net5.0</TargetFrameworks>
<TargetFrameworks>netstandard1.1;netstandard1.3;netstandard2.0;net4.5;netcoreapp3.1;net5.0</TargetFrameworks>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<RootNamespace>Serilog</RootNamespace>
Expand All @@ -19,7 +19,8 @@
<RepositoryUrl>https://github.com/serilog/serilog-sinks-seq</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<GenerateAssemblyVersionAttribute>true</GenerateAssemblyVersionAttribute>
<LangVersion>8</LangVersion>
<LangVersion>9</LangVersion>
<Nullable>enable</Nullable>
</PropertyGroup>

<PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard1.3' ">
Expand All @@ -31,25 +32,26 @@
</PropertyGroup>

<PropertyGroup Condition=" '$(TargetFramework)' == 'netcoreapp3.1' ">
<DefineConstants>$(DefineConstants);DURABLE;THREADING_TIMER</DefineConstants>
<DefineConstants>$(DefineConstants);DURABLE;THREADING_TIMER;WRITE_ALL_BYTES_ASYNC</DefineConstants>
</PropertyGroup>

<PropertyGroup Condition=" '$(TargetFramework)' == 'net5.0' ">
<DefineConstants>$(DefineConstants);DURABLE;THREADING_TIMER</DefineConstants>
<DefineConstants>$(DefineConstants);DURABLE;THREADING_TIMER;WRITE_ALL_BYTES_ASYNC</DefineConstants>
</PropertyGroup>

<PropertyGroup Condition=" '$(TargetFramework)' == 'net45' ">
<PropertyGroup Condition=" '$(TargetFramework)' == 'net4.5' ">
<DefineConstants>$(DefineConstants);DURABLE;THREADING_TIMER;HRESULTS</DefineConstants>
</PropertyGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
<ItemGroup Condition=" '$(TargetFramework)' == 'net4.5' ">
<Reference Include="System.Net.Http" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Serilog" Version="2.10.0" />
<PackageReference Include="Serilog.Sinks.PeriodicBatching" Version="2.3.0" />
<PackageReference Include="Serilog.Formatting.Compact" Version="1.1.0" />
<PackageReference Include="Nullable" Version="1.3.0" PrivateAssets="All" />
</ItemGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.1' ">
Expand Down
33 changes: 10 additions & 23 deletions src/Serilog.Sinks.Seq/Sinks/Seq/Audit/SeqAuditSink.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,38 +14,32 @@

using System;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Serilog.Core;
using Serilog.Debugging;
using Serilog.Events;
using Serilog.Formatting.Compact;
using Serilog.Formatting.Json;
using Serilog.Sinks.Seq.Http;

namespace Serilog.Sinks.Seq.Audit
{
/// <summary>
/// An <see cref="ILogEventSink"/> that synchronously propagates all <see cref="Emit"/> failures as exceptions.
/// </summary>
sealed class SeqAuditSink : ILogEventSink, IDisposable
{
readonly string _apiKey;
readonly HttpClient _httpClient;
readonly SeqIngestionApi _ingestionApi;

static readonly JsonValueFormatter JsonValueFormatter = new JsonValueFormatter("$type");
static readonly JsonValueFormatter JsonValueFormatter = new("$type");

public SeqAuditSink(
string serverUrl,
string apiKey,
HttpMessageHandler messageHandler)
public SeqAuditSink(SeqIngestionApi ingestionApi)
{
if (serverUrl == null) throw new ArgumentNullException(nameof(serverUrl));
_httpClient = messageHandler != null ? new HttpClient(messageHandler) : new HttpClient();
_httpClient.BaseAddress = new Uri(SeqApi.NormalizeServerBaseAddress(serverUrl));
_apiKey = apiKey;
_ingestionApi = ingestionApi ?? throw new ArgumentNullException(nameof(ingestionApi));
}

public void Dispose()
{
_httpClient.Dispose();
_ingestionApi.Dispose();
}

public void Emit(LogEvent logEvent)
Expand All @@ -59,15 +53,8 @@ async Task EmitAsync(LogEvent logEvent)

var payload = new StringWriter();
CompactJsonFormatter.FormatEvent(logEvent, payload, JsonValueFormatter);
payload.WriteLine();

var content = new StringContent(payload.ToString(), Encoding.UTF8, SeqApi.CompactLogEventFormatMimeType);
if (!string.IsNullOrWhiteSpace(_apiKey))
content.Headers.Add(SeqApi.ApiKeyHeaderName, _apiKey);

var result = await _httpClient.PostAsync(SeqApi.BulkUploadResource, content).ConfigureAwait(false);
if (!result.IsSuccessStatusCode)
throw new LoggingFailedException($"Received failed result {result.StatusCode} when posting events to Seq");
await _ingestionApi.IngestAsync(payload.ToString()).ConfigureAwait(false);
}
}
}
82 changes: 82 additions & 0 deletions src/Serilog.Sinks.Seq/Sinks/Seq/Batched/BatchedSeqSink.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// Copyright © Serilog Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Serilog.Events;
using Serilog.Sinks.PeriodicBatching;
using Serilog.Sinks.Seq.Http;

namespace Serilog.Sinks.Seq.Batched
{
/// <summary>
/// The default Seq sink, for use in combination with <see cref="PeriodicBatchingSink"/>.
/// </summary>
sealed class BatchedSeqSink : IBatchedLogEventSink, IDisposable
{
static readonly TimeSpan RequiredLevelCheckInterval = TimeSpan.FromMinutes(2);

readonly ConstrainedBufferedFormatter _formatter;
readonly SeqIngestionApi _ingestionApi;

DateTime _nextRequiredLevelCheckUtc = DateTime.UtcNow.Add(RequiredLevelCheckInterval);
readonly ControlledLevelSwitch _controlledSwitch;

public BatchedSeqSink(
SeqIngestionApi ingestionApi,
long? eventBodyLimitBytes,
ControlledLevelSwitch controlledSwitch)
{
_controlledSwitch = controlledSwitch ?? throw new ArgumentNullException(nameof(controlledSwitch));
_formatter = new ConstrainedBufferedFormatter(eventBodyLimitBytes);
_ingestionApi = ingestionApi ?? throw new ArgumentNullException(nameof(ingestionApi));
}

public void Dispose()
{
_ingestionApi.Dispose();
}

// The sink must emit at least one event on startup, and the server be
// configured to set a specific level, before background level checks will be performed.
public async Task OnEmptyBatchAsync()
{
if (_controlledSwitch.IsActive &&
_nextRequiredLevelCheckUtc < DateTime.UtcNow)
{
await EmitBatchAsync(Enumerable.Empty<LogEvent>());
}
}

public async Task EmitBatchAsync(IEnumerable<LogEvent> events)
{
_nextRequiredLevelCheckUtc = DateTime.UtcNow.Add(RequiredLevelCheckInterval);

var payload = new StringWriter();
foreach (var evt in events)
{
_formatter.Format(evt, payload);
}

var clefPayload = payload.ToString();

var minimumAcceptedLevel = await _ingestionApi.IngestAsync(clefPayload);

_controlledSwitch.Update(minimumAcceptedLevel);
}
}
}
Loading

0 comments on commit 5d03588

Please sign in to comment.