aws / aws/aws-lambda-dotnet

JSON log format pairs ILogger message template placeholders with state values by position, garbling ASP.NET Core hosting logs

Offen
#2,468 2 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen
bug investigating p2
Vorherrschende Sprache
C#
Sterne
1.7k
Forks
503
Ø Merge
1 T. 18 Std.
Gemergte PRs (30 T.)
21

Beschreibung

### Describe the bug

When a function uses `LoggingConfig.LogFormat: JSON` and bridges `Microsoft.Extensions.Logging.ILogger` to the Lambda logging API via `Amazon.Lambda.Logging.AspNetCore`, structured log events can come out with their JSON properties holding the **wrong values** (each property shifted to a neighboring placeholder's value).

Root cause, as far as I can tell, is a combination of two behaviors:

1. `LambdaILogger` extracts the message template from `{OriginalFormat}` and collects the state values **in state enumeration order** ([LambdaILogger.cs](https://github.com/aws/aws-lambda-dotnet/blob/master/Libraries/src/Amazon.Lambda.Logging.AspNetCore/LambdaILogger.cs)).
2. `JsonLogMessageFormatter` then pairs template placeholders with arguments **strictly by position** ([JsonLogMessageFormatter.cs](https://github.com/aws/aws-lambda-dotnet/blob/master/Libraries/src/Amazon.Lambda.RuntimeSupport/Helpers/Logging/JsonLogMessageFormatter.cs)).

The `Microsoft.Extensions.Logging` contract is that placeholders are resolved **by name** against the state key/value pairs; nothing guarantees that state enumeration order matches placeholder order. The most prominent violator ships in ASP.NET Core itself: [`HostingRequestStartingLog`](https://github.com/dotnet/aspnetcore/blob/main/src/Hosting/Hosting/src/Internal/HostingRequestStartingLog.cs) enumerates its state as `Protocol, Method, ContentType, ContentLength, Scheme, Host, PathBase, Path, QueryString`, while its template is:

```
Request starting {Protocol} {Method} {Scheme}://{Host}{PathBase}{Path}{QueryString} - {ContentType} {ContentLength}
```

So every `Request starting` log line of every ASP.NET Core app running on Lambda with JSON log format is silently garbled from the third placeholder on.

### Regression Issue

- [ ] Select this option if this issue appears to be a regression.

### Expected Behavior

Template placeholders resolved by name, as with every other `Microsoft.Extensions.Logging` sink:

```json
{
"message": "Request starting HTTP/1.1 DELETE https://api.example.com/events/123?preserve=true - application/json 0",
"Method": "DELETE",
"Scheme": "https",
"Host": "api.example.com",
"Path": "/events/123",
"QueryString": "?preserve=true",
"ContentType": "application/json",
"ContentLength": 0
}
```

### Current Behavior

Actual CloudWatch log record (values anonymized). Note `Scheme` holding the content type, `Host` holding the content length, `Path` holding the host, `ContentType` holding the path, etc.:

```json
{
"timestamp": "2026-07-04T22:43:57.529Z",
"level": "Information",
"requestId": "188cbe50-087d-4465-acf4-d4a6067ef0da",
"message": "Request starting {Protocol} DELETE application/json://0httpsapi.example.com - /events/123 ?preserve=true",
"Method": "DELETE",
"Scheme": "application/json",
"Host": 0,
"PathBase": "https",
"Path": "api.example.com",
"QueryString": "",
"ContentType": "/events/123",
"ContentLength": "?preserve=true"
}
```

Each placeholder received the state value at the same index instead of the value with the matching name (`{Scheme}` ← `ContentType`, `{Host}` ← `ContentLength`, `{PathBase}` ← `Scheme`, ...). The rendered `message` is garbled the same way.

### Reproduction Steps

Minimal ASP.NET Core app:

```csharp
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAWSLambdaHosting(LambdaEventSource.RestApi);
builder.Logging.ClearProviders();
builder.Logging.AddLambdaLogger();
var app = builder.Build();
app.MapGet("/", () => "ok");
app.Run();
```

Deploy behind API Gateway with:

```yaml
LoggingConfig:
LogFormat: JSON
```

Invoke any endpoint and inspect the `Request starting` record in CloudWatch: the `Scheme`, `Host`, `PathBase`, `Path`, `QueryString`, `ContentType` and `ContentLength` properties are shifted as shown above.

### Possible Solution

Either:

- In `LambdaILogger` (JSON branch): parse the placeholder names from `{OriginalFormat}` and emit the arguments **in placeholder order**, resolving each one by key against the state; or
- In `JsonLogMessageFormatter`: when arguments come from an `ILogger` state, match them to placeholders by name instead of by position.

### Additional Information/Context

Any `ILogger` event whose state enumeration order differs from its template placeholder order is affected — ASP.NET Core hosting logs are just the guaranteed-out-of-the-box case. Logs written through the standard `LoggerExtensions`/`LoggerMessage` paths happen to be unaffected because `FormattedLogValues` keeps both orders aligned, which is probably why this went unnoticed.

### AWS .NET SDK and/or Package version used

Amazon.Lambda.AspNetCoreServer 10.1.1
Amazon.Lambda.AspNetCoreServer.Hosting 2.1.0
Amazon.Lambda.Logging.AspNetCore 5.0.0
Amazon.Lambda.Core 3.1.0

### Targeted .NET Platform

.NET 10 (managed `dotnet10` runtime)

### Operating System and version

Amazon Linux 2023 (Lambda managed runtime)

Beitragsleitfaden

Beitragsleitfaden öffnen

Rechercherichtung

Lies Libraries/src/Amazon.Lambda.Logging.AspNetCore/LambdaILogger.cs und Libraries/src/Amazon.Lambda.RuntimeSupport/Helpers/Logging/JsonLogMessageFormatter.cs und führe anschließend die minimale ASP.NET-Core-Reproduktion mit JSON-Logging aus. Als erledigt gilt die Aufgabe, wenn der Datensatz Request starting jede JSON-Eigenschaft anhand ihres Platzhalternamens auflöst und die gerenderte Nachricht nicht mehr verschoben ist.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
aws, csharp
Bereich
backend, observability-sre
Issue-Typ
Bug
Schwierigkeit
3/5
Geschätzter Aufwand
1-2 Tage
Aktivitätsstatus
Ruhig
Klarheit
Klar beschrieben
Anfängerfreundlichkeit
70/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.