-
Notifications
You must be signed in to change notification settings - Fork 35
Expand file tree
/
Copy pathLogger.Scope.cs
More file actions
129 lines (117 loc) · 4.25 KB
/
Copy pathLogger.Scope.cs
File metadata and controls
129 lines (117 loc) · 4.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using AWS.Lambda.Powertools.Logging.Internal;
using AWS.Lambda.Powertools.Logging.Internal.Helpers;
namespace AWS.Lambda.Powertools.Logging;
public static partial class Logger
{
/// <summary>
/// Thread-safe dictionary for per-thread scope storage.
/// Uses ManagedThreadId as key to ensure isolation when Lambda processes
/// multiple concurrent requests (AWS_LAMBDA_MAX_CONCURRENCY > 1).
/// Inner dictionary is ConcurrentDictionary for thread-safe operations.
/// </summary>
private static readonly ConcurrentDictionary<int, ConcurrentDictionary<string, object>> _threadScopes = new();
/// <summary>
/// Gets the scope for the current thread.
/// Creates a new dictionary if one doesn't exist for this thread.
/// </summary>
/// <value>The scope.</value>
private static ConcurrentDictionary<string, object> Scope
{
get
{
var threadId = Environment.CurrentManagedThreadId;
return _threadScopes.GetOrAdd(threadId, _ => new ConcurrentDictionary<string, object>(StringComparer.Ordinal));
}
}
/// <summary>
/// Gets the correlation identifier from the log context.
/// </summary>
/// <value>The correlation identifier, or null if not set.</value>
public static string CorrelationId
{
get
{
if (Scope.TryGetValue(LoggingConstants.KeyCorrelationId, out var value))
{
return value?.ToString();
}
return null;
}
}
/// <summary>
/// Appending additional key to the log context.
/// </summary>
/// <param name="key">The key.</param>
/// <param name="value">The value.</param>
/// <exception cref="System.ArgumentNullException">key</exception>
/// <exception cref="System.ArgumentNullException">value</exception>
public static void AppendKey(string key, object value)
{
if (string.IsNullOrWhiteSpace(key))
throw new ArgumentNullException(nameof(key));
var convertedValue = PowertoolsLoggerHelpers.ObjectToDictionary(value) ??
throw new ArgumentNullException(nameof(value));
Scope[key] = convertedValue;
}
/// <summary>
/// Appending additional key to the log context.
/// </summary>
/// <param name="keys">The list of keys.</param>
public static void AppendKeys(IEnumerable<KeyValuePair<string, object>> keys)
{
foreach (var (key, value) in keys)
AppendKey(key, value);
}
/// <summary>
/// Appending additional key to the log context.
/// </summary>
/// <param name="keys">The list of keys.</param>
public static void AppendKeys(IEnumerable<KeyValuePair<string, string>> keys)
{
foreach (var (key, value) in keys)
AppendKey(key, value);
}
/// <summary>
/// Remove additional keys from the log context.
/// </summary>
/// <param name="keys">The list of keys.</param>
public static void RemoveKeys(params string[] keys)
{
if (keys == null) return;
foreach (var key in keys)
Scope.TryRemove(key, out _);
}
/// <summary>
/// Returns all additional keys added to the log context.
/// Returns a snapshot to ensure thread-safety during enumeration.
/// </summary>
/// <returns>IEnumerable<KeyValuePair<System.String, System.Object>>.</returns>
public static IEnumerable<KeyValuePair<string, object>> GetAllKeys()
{
// Return a snapshot to avoid concurrent modification issues
return Scope.ToArray();
}
/// <summary>
/// Removes all additional keys from the log context for the current thread.
/// </summary>
internal static void RemoveAllKeys()
{
var threadId = Environment.CurrentManagedThreadId;
if (_threadScopes.TryGetValue(threadId, out var scope))
{
scope.Clear();
}
}
/// <summary>
/// Removes a key from the log context.
/// </summary>
public static void RemoveKey(string key)
{
Scope.TryRemove(key, out _);
}
}