Skip to content

Commit 3a5f079

Browse files
committed
IDiagnosticContext.Add() -> IDiagnosticContext.Set(); more small tweaks
1 parent cee6a1a commit 3a5f079

File tree

5 files changed

+74
-23
lines changed

5 files changed

+74
-23
lines changed

src/Serilog.Extensions.Hosting/Extensions/Hosting/AmbientDiagnosticContextCollector.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,18 @@
1-
using System;
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;
216
using System.Threading;
317

418
namespace Serilog.Extensions.Hosting

src/Serilog.Extensions.Hosting/Extensions/Hosting/DiagnosticContext.cs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,15 @@
1313
// limitations under the License.
1414

1515
using System;
16+
using System.Threading;
1617

1718
namespace Serilog.Extensions.Hosting
1819
{
1920
/// <summary>
20-
/// Implements an ambient/async-local diagnostic context. Consumers should
21-
/// use <see cref="IDiagnosticContext"/> in preference to this concrete type.
21+
/// Implements an ambient diagnostic context using <see cref="AsyncLocal{T}"/>.
2222
/// </summary>
23-
public class DiagnosticContext : IDiagnosticContext
23+
/// <remarks>Consumers should use <see cref="IDiagnosticContext"/> to set context properties.</remarks>
24+
public sealed class DiagnosticContext : IDiagnosticContext
2425
{
2526
readonly ILogger _logger;
2627

@@ -34,25 +35,25 @@ public DiagnosticContext(ILogger logger)
3435
}
3536

3637
/// <summary>
37-
/// Start collecting properties to associate with the current async context. This will replace
38+
/// Start collecting properties to associate with the current diagnostic context. This will replace
3839
/// the active collector, if any.
3940
/// </summary>
40-
/// <returns>A collector that will receive events added in the current async context.</returns>
41+
/// <returns>A collector that will receive properties added in the current diagnostic context.</returns>
4142
public DiagnosticContextCollector BeginCollection()
4243
{
4344
return AmbientDiagnosticContextCollector.Begin();
4445
}
4546

46-
/// <inheritdoc cref="IDiagnosticContext.Add"/>
47-
public void Add(string propertyName, object value, bool destructureObjects = false)
47+
/// <inheritdoc cref="IDiagnosticContext.Set"/>
48+
public void Set(string propertyName, object value, bool destructureObjects = false)
4849
{
4950
if (propertyName == null) throw new ArgumentNullException(nameof(propertyName));
5051

5152
var collector = AmbientDiagnosticContextCollector.Current;
5253
if (collector != null &&
5354
(_logger ?? Log.Logger).BindProperty(propertyName, value, destructureObjects, out var property))
5455
{
55-
collector.Add(property);
56+
collector.AddOrUpdate(property);
5657
}
5758
}
5859
}

src/Serilog.Extensions.Hosting/Extensions/Hosting/DiagnosticContextCollector.cs

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,26 +9,42 @@ namespace Serilog.Extensions.Hosting
99
/// </summary>
1010
public sealed class DiagnosticContextCollector : IDisposable
1111
{
12-
readonly AmbientDiagnosticContextCollector _ambientCollector;
12+
readonly IDisposable _chainedDisposable;
1313
readonly object _propertiesLock = new object();
1414
List<LogEventProperty> _properties = new List<LogEventProperty>();
1515

16-
internal DiagnosticContextCollector(AmbientDiagnosticContextCollector ambientCollector)
16+
/// <summary>
17+
/// Construct a <see cref="DiagnosticContextCollector"/>.
18+
/// </summary>
19+
/// <param name="chainedDisposable">An object that will be disposed to signal completion/disposal of
20+
/// the collector.</param>
21+
public DiagnosticContextCollector(IDisposable chainedDisposable)
1722
{
18-
_ambientCollector = ambientCollector ?? throw new ArgumentNullException(nameof(ambientCollector));
23+
_chainedDisposable = chainedDisposable ?? throw new ArgumentNullException(nameof(chainedDisposable));
1924
}
2025

2126
/// <summary>
2227
/// Add the property to the context.
2328
/// </summary>
2429
/// <param name="property">The property to add.</param>
25-
public void Add(LogEventProperty property)
30+
public void AddOrUpdate(LogEventProperty property)
2631
{
2732
if (property == null) throw new ArgumentNullException(nameof(property));
2833

2934
lock (_propertiesLock)
3035
{
31-
_properties?.Add(property);
36+
if (_properties == null) return;
37+
38+
for (var i = 0; i < _properties.Count; ++i)
39+
{
40+
if (_properties[i].Name == property.Name)
41+
{
42+
_properties[i] = property;
43+
return;
44+
}
45+
}
46+
47+
_properties.Add(property);
3248
}
3349
}
3450

@@ -53,7 +69,7 @@ public bool TryComplete(out List<LogEventProperty> properties)
5369
/// <inheritdoc/>
5470
public void Dispose()
5571
{
56-
_ambientCollector.Dispose();
72+
_chainedDisposable.Dispose();
5773
}
5874
}
5975
}

src/Serilog.Extensions.Hosting/IDiagnosticContext.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,13 @@ namespace Serilog
2020
public interface IDiagnosticContext
2121
{
2222
/// <summary>
23-
/// Add the specified property to the request's diagnostic payload.
23+
/// Set the specified property on the current diagnostic context. The property will be collected
24+
/// and attached to the event emitted at the completion of the context.
2425
/// </summary>
2526
/// <param name="propertyName">The name of the property. Must be non-empty.</param>
2627
/// <param name="value">The property value.</param>
2728
/// <param name="destructureObjects">If true, the value will be serialized as structured
2829
/// data if possible; if false, the object will be recorded as a scalar or simple array.</param>
29-
void Add(string propertyName, object value, bool destructureObjects = false);
30+
void Set(string propertyName, object value, bool destructureObjects = false);
3031
}
3132
}
Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
using System;
2+
using System.Linq;
23
using System.Threading.Tasks;
4+
using Serilog.Events;
35
using Serilog.Extensions.Hosting.Tests.Support;
46
using Xunit;
57

8+
// ReSharper disable PossibleNullReferenceException
9+
610
namespace Serilog.Extensions.Hosting.Tests
711
{
812
public class DiagnosticContextTests
913
{
1014
[Fact]
11-
public void AddIsSafeWhenNoContextIsActive()
15+
public void SetIsSafeWhenNoContextIsActive()
1216
{
1317
var dc = new DiagnosticContext(Some.Logger());
14-
dc.Add(Some.String("name"), Some.Int32());
18+
dc.Set(Some.String("name"), Some.Int32());
1519
}
1620

1721
[Fact]
@@ -20,19 +24,34 @@ public async Task PropertiesAreCollectedInAnActiveContext()
2024
var dc = new DiagnosticContext(Some.Logger());
2125

2226
var collector = dc.BeginCollection();
23-
dc.Add(Some.String("name"), Some.Int32());
27+
dc.Set(Some.String("first"), Some.Int32());
2428
await Task.Delay(TimeSpan.FromMilliseconds(10));
25-
dc.Add(Some.String("name"), Some.Int32());
29+
dc.Set(Some.String("second"), Some.Int32());
2630

2731
Assert.True(collector.TryComplete(out var properties));
28-
Assert.Equal(2, properties.Count);
32+
Assert.Equal(2, properties.Count());
2933

3034
Assert.False(collector.TryComplete(out _));
3135

3236
collector.Dispose();
3337

34-
dc.Add(Some.String("name"), Some.Int32());
38+
dc.Set(Some.String("third"), Some.Int32());
3539
Assert.False(collector.TryComplete(out _));
3640
}
41+
42+
[Fact]
43+
public void ExistingPropertiesCanBeUpdated()
44+
{
45+
var dc = new DiagnosticContext(Some.Logger());
46+
47+
var collector = dc.BeginCollection();
48+
dc.Set("name", 10);
49+
dc.Set("name", 20);
50+
51+
Assert.True(collector.TryComplete(out var properties));
52+
var prop = Assert.Single(properties);
53+
var scalar = Assert.IsType<ScalarValue>(prop.Value);
54+
Assert.Equal(20, scalar.Value);
55+
}
3756
}
3857
}

0 commit comments

Comments
 (0)