Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

7.0.0 Release #212

Merged
merged 9 commits into from
Mar 6, 2024
2 changes: 1 addition & 1 deletion global.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"sdk": {
"version": "7.0.100",
"version": "8.0.201",
"rollForward": "latestFeature"
}
}
10 changes: 5 additions & 5 deletions sample/BlazorWasm/BlazorWasm.csproj
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="7.0.11" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="7.0.11" PrivateAssets="all" />
<PackageReference Include="serilog.extensions.logging" Version="7.0.0" />
<PackageReference Include="serilog.sinks.browserconsole" Version="1.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="8.0.0" PrivateAssets="all" />
<PackageReference Include="serilog.extensions.logging" Version="8.0.0" />
<PackageReference Include="serilog.sinks.browserconsole" Version="2.0.0" />
</ItemGroup>

<ItemGroup>
Expand Down
4 changes: 2 additions & 2 deletions sample/Sample/Sample.csproj
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<OutputType>Exe</OutputType>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<CheckEolTargetFramework>false</CheckEolTargetFramework>
</PropertyGroup>

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

<ItemGroup>
Expand Down
5 changes: 2 additions & 3 deletions src/Serilog.Sinks.Seq/SeqLoggerConfigurationExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
using Serilog.Sinks.Seq;
using System.Net.Http;
using Serilog.Formatting;
using Serilog.Formatting.Compact;
using Serilog.Sinks.PeriodicBatching;
using Serilog.Sinks.Seq.Batched;
using Serilog.Sinks.Seq.Audit;
Expand All @@ -36,8 +35,8 @@ public static class SeqLoggerConfigurationExtensions
const int DefaultBatchPostingLimit = 1000;
static readonly TimeSpan DefaultPeriod = TimeSpan.FromSeconds(2);
const int DefaultQueueSizeLimit = 100000;
static ITextFormatter CreateDefaultFormatter() => new CompactJsonFormatter(new("$type"));

static ITextFormatter CreateDefaultFormatter() => new SeqCompactJsonFormatter();
/// <summary>
/// Write log events to a <a href="https://datalust.co/seq">Seq</a> server.
/// </summary>
Expand Down
5 changes: 2 additions & 3 deletions src/Serilog.Sinks.Seq/Serilog.Sinks.Seq.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<Description>A Serilog sink that writes events to Seq using newline-delimited JSON and HTTP/HTTPS.</Description>
<VersionPrefix>6.0.0</VersionPrefix>
<VersionPrefix>7.0.0</VersionPrefix>
<Authors>Serilog Contributors;Serilog.Sinks.Seq Contributors;Datalust Pty Ltd</Authors>
<Copyright>Copyright © Serilog Contributors, Serilog.Sinks.Seq Contributors, Datalust Pty Ltd.</Copyright>
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks>
Expand Down Expand Up @@ -30,8 +30,7 @@

<ItemGroup>
<PackageReference Include="Serilog" Version="3.1.1" />
<PackageReference Include="Serilog.Sinks.PeriodicBatching" Version="3.1.0" />
<PackageReference Include="Serilog.Formatting.Compact" Version="2.0.0" />
<PackageReference Include="Serilog.Sinks.PeriodicBatching" Version="4.0.0" />
<PackageReference Include="Nullable" Version="1.3.1" PrivateAssets="All" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
</ItemGroup>
Expand Down
18 changes: 12 additions & 6 deletions src/Serilog.Sinks.Seq/Sinks/Seq/Http/SeqIngestionApiClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ sealed class SeqIngestionApiClient : SeqIngestionApi
{
const string BulkUploadResource = "api/events/raw";
const string ApiKeyHeaderName = "X-Seq-ApiKey";

readonly string? _apiKey;
readonly HttpClient _httpClient;

Expand All @@ -50,6 +50,7 @@ public SeqIngestionApiClient(string serverUrl, string? apiKey, HttpMessageHandle
_httpClient = new HttpClient();
}
#endif

#if SOCKETS_HTTP_HANDLER_ALWAYS_DEFAULT
else
{
Expand All @@ -59,14 +60,19 @@ public SeqIngestionApiClient(string serverUrl, string? apiKey, HttpMessageHandle
// require that the Seq API be accessed at a different IP address. Setting a timeout here puts
// an upper bound on the duration of DNS-related outages, while hopefully incurring only infrequent
// connection reestablishment costs.
PooledConnectionLifetime = TimeSpan.FromMinutes(5)
PooledConnectionLifetime = TimeSpan.FromMinutes(5),

// Don't trace the sink's own requests. On platforms that use alternative message handler implementations
// by default, the caller needs to do this manually and pass a handler through. Where `SocketsHttpHandler`
// is the default, we can safely set this without inadvertently causing behavior changes.
ActivityHeadersPropagator = null
});
}
#else
else
{
_httpClient = new HttpClient();
}
else
{
_httpClient = new HttpClient();
}
#endif

_httpClient.BaseAddress = new Uri(NormalizeServerBaseAddress(serverUrl));
Expand Down
164 changes: 164 additions & 0 deletions src/Serilog.Sinks.Seq/Sinks/Seq/SeqCompactJsonFormatter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
// Copyright 2016 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.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using Serilog.Events;
using Serilog.Formatting;
using Serilog.Formatting.Json;
using Serilog.Parsing;
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable PossibleMultipleEnumeration

namespace Serilog.Sinks.Seq;

/// <summary>
/// An <see cref="ITextFormatter"/> that writes events in a compact JSON format.
/// </summary>
/// <remarks>Modified from <c>Serilog.Formatting.Compact.CompactJsonFormatter</c> to add
/// implicit SerilogTracing span support.</remarks>
public class SeqCompactJsonFormatter: ITextFormatter
{
readonly JsonValueFormatter _valueFormatter = new("$type");

/// <summary>
/// Format the log event into the output. Subsequent events will be newline-delimited.
/// </summary>
/// <param name="logEvent">The event to format.</param>
/// <param name="output">The output.</param>
public void Format(LogEvent logEvent, TextWriter output)
{
FormatEvent(logEvent, output, _valueFormatter);
output.WriteLine();
}

/// <summary>
/// Format the log event into the output.
/// </summary>
/// <param name="logEvent">The event to format.</param>
/// <param name="output">The output.</param>
/// <param name="valueFormatter">A value formatter for <see cref="LogEventPropertyValue"/>s on the event.</param>
public static void FormatEvent(LogEvent logEvent, TextWriter output, JsonValueFormatter valueFormatter)
{
if (logEvent == null) throw new ArgumentNullException(nameof(logEvent));
if (output == null) throw new ArgumentNullException(nameof(output));
if (valueFormatter == null) throw new ArgumentNullException(nameof(valueFormatter));

output.Write("{\"@t\":\"");
output.Write(logEvent.Timestamp.UtcDateTime.ToString("O"));
output.Write("\",\"@mt\":");
JsonValueFormatter.WriteQuotedJsonString(logEvent.MessageTemplate.Text, output);

var tokensWithFormat = logEvent.MessageTemplate.Tokens
.OfType<PropertyToken>()
.Where(pt => pt.Format != null);

// Better not to allocate an array in the 99.9% of cases where this is false
// ReSharper disable once PossibleMultipleEnumeration
if (tokensWithFormat.Any())
{
output.Write(",\"@r\":[");
var delim = "";
foreach (var r in tokensWithFormat)
{
output.Write(delim);
delim = ",";
var space = new StringWriter();
r.Render(logEvent.Properties, space, CultureInfo.InvariantCulture);
JsonValueFormatter.WriteQuotedJsonString(space.ToString(), output);
}
output.Write(']');
}

if (logEvent.Level != LogEventLevel.Information)
{
output.Write(",\"@l\":\"");
output.Write(logEvent.Level);
output.Write('\"');
}

if (logEvent.Exception != null)
{
output.Write(",\"@x\":");
JsonValueFormatter.WriteQuotedJsonString(logEvent.Exception.ToString(), output);
}

if (logEvent.TraceId != null)
{
output.Write(",\"@tr\":\"");
output.Write(logEvent.TraceId.Value.ToHexString());
output.Write('\"');
}

if (logEvent.SpanId != null)
{
output.Write(",\"@sp\":\"");
output.Write(logEvent.SpanId.Value.ToHexString());
output.Write('\"');
}

var skipSpanProperties = false;
if (logEvent is {TraceId: not null, SpanId: not null} &&
logEvent.Properties.TryGetValue("SpanStartTimestamp", out var st) &&
st is ScalarValue { Value: DateTime spanStartTimestamp })
{
skipSpanProperties = true;

output.Write(",\"@st\":\"");
output.Write(spanStartTimestamp.ToString("o"));
output.Write('\"');

if (logEvent.Properties.TryGetValue("ParentSpanId", out var ps) &&
ps is ScalarValue { Value: ActivitySpanId parentSpanId })
{
output.Write(",\"@ps\":\"");
output.Write(parentSpanId.ToHexString());
output.Write('\"');
}

if (logEvent.Properties.TryGetValue("SpanKind", out var sk) &&
sk is ScalarValue { Value: ActivityKind spanKind } &&
spanKind != ActivityKind.Internal)
{
output.Write(",\"@sk\":\"");
output.Write(spanKind);
output.Write('\"');
}
}

foreach (var property in logEvent.Properties)
{
var name = property.Key;

if (skipSpanProperties && name is "SpanStartTimestamp" or "ParentSpanId" or "SpanKind")
continue;

if (name.Length > 0 && name[0] == '@')
{
// Escape first '@' by doubling
name = '@' + name;
}

output.Write(',');
JsonValueFormatter.WriteQuotedJsonString(name, output);
output.Write(':');
valueFormatter.Format(property.Value, output);
}

output.Write('}');
}
}
7 changes: 3 additions & 4 deletions test/Serilog.Sinks.Seq.Tests/Audit/SeqAuditSinkTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using System.Threading.Tasks;
using Serilog.Debugging;
using Serilog.Events;
using Serilog.Formatting.Compact;
using Serilog.Sinks.Seq.Audit;
using Serilog.Sinks.Seq.Tests.Support;
using Xunit;
Expand Down Expand Up @@ -40,7 +39,7 @@ public void RemoteCommunicationErrorsPropagateToCallerWhenAuditing()
public void AuditSinkDisposesIngestionApi()
{
var api = new TestIngestionApi();
var sink = new SeqAuditSink(api, new CompactJsonFormatter());
var sink = new SeqAuditSink(api, new SeqCompactJsonFormatter());
Assert.False(api.IsDisposed);

sink.Dispose();
Expand All @@ -54,7 +53,7 @@ public async Task AuditSinkEmitsIndividualEvents()
LogEvent evt1 = Some.InformationEvent("first"), evt2 = Some.InformationEvent("second");

var api = new TestIngestionApi();
var sink = new SeqAuditSink(api, new CompactJsonFormatter());
var sink = new SeqAuditSink(api, new SeqCompactJsonFormatter());

sink.Emit(evt1);
sink.Emit(evt2);
Expand All @@ -71,7 +70,7 @@ public void AuditSinkPropagatesExceptions()
{
var expected = new Exception("Test");
var api = new TestIngestionApi(_ => throw expected);
var sink = new SeqAuditSink(api, new CompactJsonFormatter());
var sink = new SeqAuditSink(api, new SeqCompactJsonFormatter());

var thrown = Assert.Throws<AggregateException>(() => sink.Emit(Some.InformationEvent()));

Expand Down
7 changes: 3 additions & 4 deletions test/Serilog.Sinks.Seq.Tests/Batched/BatchedSeqSinkTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using System.Threading.Tasks;
using Serilog.Core;
using Serilog.Events;
using Serilog.Formatting.Compact;
using Serilog.Sinks.Seq.Batched;
using Serilog.Sinks.Seq.Http;
using Serilog.Sinks.Seq.Tests.Support;
Expand All @@ -16,7 +15,7 @@ public class BatchedSeqSinkTests
public void BatchedSinkDisposesIngestionApi()
{
var api = new TestIngestionApi();
var sink = new BatchedSeqSink(api, new CompactJsonFormatter(), null, new ControlledLevelSwitch());
var sink = new BatchedSeqSink(api, new SeqCompactJsonFormatter(), null, new ControlledLevelSwitch());
Assert.False(api.IsDisposed);

sink.Dispose();
Expand All @@ -28,7 +27,7 @@ public void BatchedSinkDisposesIngestionApi()
public async Task EventsAreFormattedIntoPayloads()
{
var api = new TestIngestionApi();
var sink = new BatchedSeqSink(api, new CompactJsonFormatter(), null, new ControlledLevelSwitch());
var sink = new BatchedSeqSink(api, new SeqCompactJsonFormatter(), null, new ControlledLevelSwitch());

await sink.EmitBatchAsync(new[]
{
Expand All @@ -48,7 +47,7 @@ public async Task MinimumLevelIsControlled()
const LogEventLevel originalLevel = LogEventLevel.Debug, newLevel = LogEventLevel.Error;
var levelSwitch = new LoggingLevelSwitch(originalLevel);
var api = new TestIngestionApi(_ => Task.FromResult(new IngestionResult(true, HttpStatusCode.Accepted, newLevel)));
var sink = new BatchedSeqSink(api, new CompactJsonFormatter(), null, new ControlledLevelSwitch(levelSwitch));
var sink = new BatchedSeqSink(api, new SeqCompactJsonFormatter(), null, new ControlledLevelSwitch(levelSwitch));

await sink.EmitBatchAsync(new[] { Some.InformationEvent() });

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.IO;
using Serilog.Formatting.Compact;
using Serilog.Sinks.Seq.Tests.Support;
using Xunit;

Expand All @@ -11,7 +10,7 @@ public class ConstrainedBufferedFormatterTests
public void EventsAreFormattedIntoCompactJsonPayloads()
{
var evt = Some.LogEvent("Hello, {Name}!", "Alice");
var formatter = new ConstrainedBufferedFormatter(null, new CompactJsonFormatter());
var formatter = new ConstrainedBufferedFormatter(null, new SeqCompactJsonFormatter());
var json = new StringWriter();
formatter.Format(evt, json);
Assert.Contains("Name\":\"Alice", json.ToString());
Expand All @@ -21,7 +20,7 @@ public void EventsAreFormattedIntoCompactJsonPayloads()
public void PlaceholdersAreLoggedWhenCompactJsonRenderingFails()
{
var evt = Some.LogEvent(new NastyException(), "Hello, {Name}!", "Alice");
var formatter = new ConstrainedBufferedFormatter(null, new CompactJsonFormatter());
var formatter = new ConstrainedBufferedFormatter(null, new SeqCompactJsonFormatter());
var json = new StringWriter();
formatter.Format(evt, json);
var jsonString = json.ToString();
Expand All @@ -33,7 +32,7 @@ public void PlaceholdersAreLoggedWhenCompactJsonRenderingFails()
public void PlaceholdersAreLoggedWhenTheEventSizeLimitIsExceeded()
{
var evt = Some.LogEvent("Hello, {Name}!", new string('a', 10000));
var formatter = new ConstrainedBufferedFormatter(2000, new CompactJsonFormatter());
var formatter = new ConstrainedBufferedFormatter(2000, new SeqCompactJsonFormatter());
var json = new StringWriter();
formatter.Format(evt, json);
var jsonString = json.ToString();
Expand Down
Loading