Skip to content

feat(logging): Structured scope support for Lambda JSON log format in Amazon.Lambda.Logging.AspNetCore - #2530

Open
Lanayx wants to merge 7 commits into
aws:masterfrom
Lanayx:master
Open

feat(logging): Structured scope support for Lambda JSON log format in Amazon.Lambda.Logging.AspNetCore#2530
Lanayx wants to merge 7 commits into
aws:masterfrom
Lanayx:master

Conversation

@Lanayx

@Lanayx Lanayx commented Aug 14, 2026

Copy link
Copy Markdown

Scope properties were silently dropped when AWS_LAMBDA_LOG_FORMAT=JSON. Addresses aws/aws-lambda-dotnet#2122. The final contribution should target aws/aws-lambda-dotnet:master. Closes #2122.

Changes

  • LambdaILogger.cs — In the JSON format path, when IncludeScopes=true, iterates the ScopeProvider and for each scope implementing IEnumerable<KeyValuePair<string, object>>, appends {key} placeholders to the message template and the corresponding values to the parameters array. This is necessary because the Lambda JSON formatter (RuntimeSupport) matches template placeholders positionally to args to emit named JSON properties — values without a matching placeholder are ignored. Non-structured scopes (plain strings etc.), null keys, and {OriginalFormat} entries are silently skipped. Non-JSON / scopes-disabled paths are unchanged.

  • LoggingTests.cs — Six focused tests covering: single KV scope, nested scopes, scopes disabled, no-scope template preservation, null scope value, and non-structured scope.

  • README.md — Documents structured scope behavior in Lambda JSON mode.

Example

// AWS_LAMBDA_LOG_FORMAT=JSON, IncludeScopes=true
using (logger.BeginScope(new Dictionary<string, object> { ["RequestId"] = "abc-123", ["UserId"] = 42 }))
{
    logger.LogInformation("Order {OrderId} placed", orderId);
    // Emits JSON with RequestId, UserId, and OrderId as named properties.
}

Scope properties are appended after message-template properties, so message positional args are unaffected. Nested scopes are collected in provider-enumeration order (outermost first).

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

Copilot AI and others added 3 commits August 14, 2026 03:07
When AWS_LAMBDA_LOG_FORMAT=JSON and IncludeScopes=true, scope state objects
implementing IEnumerable<KeyValuePair<string, object>> have their key/value
entries appended to the message template (as {key} placeholders) and the
parameters array, so they are emitted as named JSON properties by the Lambda
JSON formatter.

Non-structured scopes are silently ignored. Existing behavior (scopes disabled,
text-format logging, no scopes) is unchanged.

Closes aws#2122

Co-authored-by: Lanayx <3329606+Lanayx@users.noreply.github.com>
…port

feat(logging): Structured scope support for Lambda JSON log format in Amazon.Lambda.Logging.AspNetCore
@Lanayx
Lanayx requested review from a team as code owners August 14, 2026 03:25
@Lanayx
Lanayx requested review from GarrettBeatty and normj August 14, 2026 03:25

@GarrettBeatty GarrettBeatty left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ This is an automated AI review for a first pass — please check for accuracy.

Thanks for the contribution! A few findings from an adversarial pass over the diff (head 1347570). Verdict: 4 findings (no blocking, but a couple worth addressing before merge).

1. [major] Unsanitized scope keys injected as template placeholdersLambdaILogger.cs, sb.Append($" {{{entry.Key}}}"). A scope key containing :, {, }, or whitespace is emitted verbatim into the message template (e.g. key "Order:Id"{Order:Id}, where : is the MEL format separator; "a b"{a b}). This can malform the placeholder token and mis-bind positional parameters. There is no key validation — consider skipping or sanitizing keys that aren't valid template property names.

2. [major] Scope / message-template key collisionLambdaILogger.cs, same append. A scope key equal to a message-template key (message {Name} + scope key Name) appends a duplicate {Name} placeholder bound to a different positional arg, producing ambiguous/duplicate JSON property emission. There's no collision handling.

3. [major] Missing AutoVer change file.autover/changes/. LambdaILogger.cs is a shipped source change and .autover/autover.json is present, so repo convention requires a change-file entry (generated via the AutoVer CLI). This PR doesn't include one; it isn't test-only, so "Release Not Needed" doesn't apply.

4. [major – testing] No end-to-end JSON emission testLoggingTests.cs, the 6 new [Fact]s. The test harness formats output as "{level}: {message}: parameter count: {N}" and never invokes the real Lambda JSON formatter, so the core behavior (positional placeholder → named JSON property binding, and null scope-value emission) is asserted only by parameter count, never by inspecting emitted JSON. A test that drives state+scopes through the real formatter and asserts the resulting JSON keys/values would close this gap.

Copilot AI and others added 3 commits September 8, 2026 17:20
…ver change file

Co-authored-by: Lanayx <3329606+Lanayx@users.noreply.github.com>
Fix scope key sanitization, collisions, and add e2e JSON tests + auto…
…erge-conflicts

# Conflicts:
#	Libraries/src/Amazon.Lambda.Logging.AspNetCore/LambdaILogger.cs

Co-authored-by: Lanayx <3329606+Lanayx@users.noreply.github.com>
Merge upstream master to resolve mergeable_state=dirty on PR aws#2530
@Lanayx
Lanayx requested a review from GarrettBeatty September 9, 2026 00:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support scopes with Amazon.Lambda.Logging.AspNetCore JSON logger

3 participants