Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 12 additions & 10 deletions libraries/src/AWS.Lambda.Powertools.Logging/Logger.Scope.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,21 @@ public static partial class Logger
/// 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, Dictionary<string, object>> _threadScopes = new();
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 IDictionary<string, object> Scope
private static ConcurrentDictionary<string, object> Scope
{
get
{
var threadId = Environment.CurrentManagedThreadId;
return _threadScopes.GetOrAdd(threadId, _ => new Dictionary<string, object>(StringComparer.Ordinal));
return _threadScopes.GetOrAdd(threadId, _ => new ConcurrentDictionary<string, object>(StringComparer.Ordinal));
}
}

Expand Down Expand Up @@ -58,9 +59,10 @@ public static void AppendKey(string key, object value)
{
if (string.IsNullOrWhiteSpace(key))
throw new ArgumentNullException(nameof(key));
Scope[key] = PowertoolsLoggerHelpers.ObjectToDictionary(value) ??

var convertedValue = PowertoolsLoggerHelpers.ObjectToDictionary(value) ??
throw new ArgumentNullException(nameof(value));
Scope[key] = convertedValue;
}

/// <summary>
Expand Down Expand Up @@ -91,17 +93,18 @@ public static void RemoveKeys(params string[] keys)
{
if (keys == null) return;
foreach (var key in keys)
if (Scope.ContainsKey(key))
Scope.Remove(key);
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&lt;KeyValuePair&lt;System.String, System.Object&gt;&gt;.</returns>
public static IEnumerable<KeyValuePair<string, object>> GetAllKeys()
{
return Scope.AsEnumerable();
// Return a snapshot to avoid concurrent modification issues
return Scope.ToArray();
}

/// <summary>
Expand All @@ -121,7 +124,6 @@ internal static void RemoveAllKeys()
/// </summary>
public static void RemoveKey(string key)
{
if (Scope.ContainsKey(key))
Scope.Remove(key);
Scope.TryRemove(key, out _);
}
}
Loading