Skip to content

Commit 130fceb

Browse files
snakefoot304NotModified
authored andcommitted
Added "Properties" property on Logger for reading and editing properties. (#3430)
* Logger - Properties added using WithProperty can now be inspected safely * small code improvement
1 parent 705c39c commit 130fceb

File tree

4 files changed

+278
-34
lines changed

4 files changed

+278
-34
lines changed

src/NLog/Config/LoggingConfiguration.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public class LoggingConfiguration
6161
/// <summary>
6262
/// Variables defined in xml or in API. name is case case insensitive.
6363
/// </summary>
64-
private readonly Dictionary<string, SimpleLayout> _variables = new Dictionary<string, SimpleLayout>(StringComparer.OrdinalIgnoreCase);
64+
private readonly ThreadSafeDictionary<string, SimpleLayout> _variables = new ThreadSafeDictionary<string, SimpleLayout>(StringComparer.OrdinalIgnoreCase);
6565

6666
/// <summary>
6767
/// Gets the factory that will be configured
@@ -812,10 +812,7 @@ private List<ISupportsInitialize> GetSupportsInitializes(bool reverse = false)
812812
/// <param name="masterVariables">Master variables dictionary</param>
813813
internal void CopyVariables(IDictionary<string, SimpleLayout> masterVariables)
814814
{
815-
foreach (var variable in masterVariables)
816-
{
817-
Variables[variable.Key] = variable.Value;
818-
}
815+
_variables.CopyFrom(masterVariables);
819816
}
820817

821818
/// <summary>

src/NLog/GlobalDiagnosticsContext.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ namespace NLog
4343
/// </summary>
4444
public static class GlobalDiagnosticsContext
4545
{
46+
private static readonly object _lockObject = new object();
4647
private static Dictionary<string, object> _dict = new Dictionary<string, object>();
4748
private static Dictionary<string, object> _dictReadOnly; // Reset cache on change
4849

@@ -63,7 +64,7 @@ public static void Set(string item, string value)
6364
/// <param name="value">Item value.</param>
6465
public static void Set(string item, object value)
6566
{
66-
lock (_dict)
67+
lock (_lockObject)
6768
{
6869
bool requireCopyOnWrite = _dictReadOnly != null && !_dict.ContainsKey(item); // Overwiting existing value is ok (no resize)
6970
GetWritableDict(requireCopyOnWrite)[item] = value;
@@ -129,7 +130,7 @@ public static bool Contains(string item)
129130
/// <param name="item">Item name.</param>
130131
public static void Remove(string item)
131132
{
132-
lock (_dict)
133+
lock (_lockObject)
133134
{
134135
bool requireCopyOnWrite = _dictReadOnly != null && _dict.ContainsKey(item);
135136
GetWritableDict(requireCopyOnWrite).Remove(item);
@@ -141,7 +142,7 @@ public static void Remove(string item)
141142
/// </summary>
142143
public static void Clear()
143144
{
144-
lock (_dict)
145+
lock (_lockObject)
145146
{
146147
bool requireCopyOnWrite = _dictReadOnly != null && _dict.Count > 0;
147148
GetWritableDict(requireCopyOnWrite, true).Clear();
@@ -153,7 +154,7 @@ private static Dictionary<string, object> GetReadOnlyDict()
153154
var readOnly = _dictReadOnly;
154155
if (readOnly == null)
155156
{
156-
lock (_dict)
157+
lock (_lockObject)
157158
{
158159
readOnly = _dictReadOnly = _dict;
159160
}
Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
//
2+
// Copyright (c) 2004-2019 Jaroslaw Kowalski <jaak@jkowalski.net>, Kim Christensen, Julian Verdurmen
3+
//
4+
// All rights reserved.
5+
//
6+
// Redistribution and use in source and binary forms, with or without
7+
// modification, are permitted provided that the following conditions
8+
// are met:
9+
//
10+
// * Redistributions of source code must retain the above copyright notice,
11+
// this list of conditions and the following disclaimer.
12+
//
13+
// * Redistributions in binary form must reproduce the above copyright notice,
14+
// this list of conditions and the following disclaimer in the documentation
15+
// and/or other materials provided with the distribution.
16+
//
17+
// * Neither the name of Jaroslaw Kowalski nor the names of its
18+
// contributors may be used to endorse or promote products derived from this
19+
// software without specific prior written permission.
20+
//
21+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
31+
// THE POSSIBILITY OF SUCH DAMAGE.
32+
//
33+
34+
namespace NLog.Internal
35+
{
36+
using System;
37+
using System.Collections;
38+
using System.Collections.Generic;
39+
using System.Linq;
40+
41+
internal class ThreadSafeDictionary<TKey, TValue> : IDictionary<TKey, TValue>
42+
{
43+
private readonly object _lockObject = new object();
44+
private readonly IEqualityComparer<TKey> _comparer;
45+
private Dictionary<TKey, TValue> _dict;
46+
private Dictionary<TKey, TValue> _dictReadOnly; // Reset cache on change
47+
48+
public ThreadSafeDictionary()
49+
:this(EqualityComparer<TKey>.Default)
50+
{
51+
}
52+
53+
public ThreadSafeDictionary(IEqualityComparer<TKey> comparer)
54+
{
55+
_comparer = comparer;
56+
_dict = new Dictionary<TKey, TValue>(_comparer);
57+
}
58+
59+
public ThreadSafeDictionary(ThreadSafeDictionary<TKey, TValue> source)
60+
{
61+
_comparer = source._comparer;
62+
_dict = source.GetReadOnlyDict();
63+
GetWritableDict(); // Clone
64+
}
65+
66+
public TValue this[TKey key]
67+
{
68+
get => GetReadOnlyDict()[key];
69+
set
70+
{
71+
lock (_lockObject)
72+
{
73+
GetWritableDict()[key] = value;
74+
}
75+
}
76+
}
77+
78+
public ICollection<TKey> Keys => GetReadOnlyDict().Keys;
79+
80+
public ICollection<TValue> Values => GetReadOnlyDict().Values;
81+
82+
public int Count => GetReadOnlyDict().Count;
83+
84+
public bool IsReadOnly => false;
85+
86+
public void Add(TKey key, TValue value)
87+
{
88+
lock (_lockObject)
89+
{
90+
GetWritableDict().Add(key, value);
91+
}
92+
}
93+
94+
public void Add(KeyValuePair<TKey, TValue> item)
95+
{
96+
lock (_lockObject)
97+
{
98+
GetWritableDict().Add(item.Key, item.Value);
99+
}
100+
}
101+
102+
public void Clear()
103+
{
104+
lock (_lockObject)
105+
{
106+
GetWritableDict(true);
107+
}
108+
}
109+
110+
public bool Contains(KeyValuePair<TKey, TValue> item)
111+
{
112+
return GetReadOnlyDict().Contains(item);
113+
}
114+
115+
public bool ContainsKey(TKey key)
116+
{
117+
return GetReadOnlyDict().ContainsKey(key);
118+
}
119+
120+
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
121+
{
122+
((IDictionary<TKey,TValue>)GetReadOnlyDict()).CopyTo(array, arrayIndex);
123+
}
124+
125+
public void CopyFrom(IDictionary<TKey, TValue> source)
126+
{
127+
if (!ReferenceEquals(this, source) && source?.Count > 0)
128+
{
129+
lock (_lockObject)
130+
{
131+
var destDict = GetWritableDict();
132+
foreach (var item in source)
133+
destDict[item.Key] = item.Value;
134+
}
135+
}
136+
}
137+
138+
public bool Remove(TKey key)
139+
{
140+
lock (_lockObject)
141+
{
142+
return GetWritableDict().Remove(key);
143+
}
144+
}
145+
146+
public bool Remove(KeyValuePair<TKey, TValue> item)
147+
{
148+
lock (_lockObject)
149+
{
150+
return GetWritableDict().Remove(item);
151+
}
152+
}
153+
154+
public bool TryGetValue(TKey key, out TValue value)
155+
{
156+
return GetReadOnlyDict().TryGetValue(key, out value);
157+
}
158+
159+
IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator()
160+
{
161+
return GetReadOnlyDict().GetEnumerator();
162+
}
163+
164+
IEnumerator IEnumerable.GetEnumerator()
165+
{
166+
return GetReadOnlyDict().GetEnumerator();
167+
}
168+
169+
public Enumerator GetEnumerator()
170+
{
171+
return new Enumerator(GetReadOnlyDict().GetEnumerator());
172+
}
173+
174+
public struct Enumerator : IEnumerator<KeyValuePair<TKey, TValue>>
175+
{
176+
Dictionary<TKey, TValue>.Enumerator _enumerator;
177+
178+
public Enumerator(Dictionary<TKey, TValue>.Enumerator enumerator)
179+
{
180+
_enumerator = enumerator;
181+
}
182+
183+
public KeyValuePair<TKey, TValue> Current => _enumerator.Current;
184+
185+
object IEnumerator.Current => _enumerator.Current;
186+
187+
public void Dispose()
188+
{
189+
_enumerator.Dispose();
190+
}
191+
192+
public bool MoveNext()
193+
{
194+
return _enumerator.MoveNext();
195+
}
196+
197+
void IEnumerator.Reset()
198+
{
199+
((IEnumerator)_enumerator).Reset();
200+
}
201+
}
202+
203+
private Dictionary<TKey, TValue> GetReadOnlyDict()
204+
{
205+
var readOnly = _dictReadOnly;
206+
if (readOnly == null)
207+
{
208+
lock (_lockObject)
209+
{
210+
readOnly = _dictReadOnly = _dict;
211+
}
212+
}
213+
return readOnly;
214+
}
215+
216+
private IDictionary<TKey, TValue> GetWritableDict(bool clearDictionary = false)
217+
{
218+
var newDict = new Dictionary<TKey, TValue>(clearDictionary ? 0 : _dict.Count + 1, _comparer);
219+
if (!clearDictionary)
220+
{
221+
// Less allocation with enumerator than Dictionary-constructor
222+
foreach (var item in _dict)
223+
newDict[item.Key] = item.Value;
224+
}
225+
_dict = newDict;
226+
_dictReadOnly = null;
227+
return newDict;
228+
}
229+
}
230+
}

0 commit comments

Comments
 (0)