Skip to content

Commit e2a7dae

Browse files
committed
update aot logs
1 parent 67c3999 commit e2a7dae

File tree

2 files changed

+144
-124
lines changed

2 files changed

+144
-124
lines changed

docs/getting-started/logger/aot.md

Lines changed: 144 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ description: Getting started with Logging in Native AOT applications
55

66
# Getting Started with AWS Lambda Powertools for .NET Logger in Native AOT
77

8-
This tutorial shows you how to set up an AWS Lambda project using Native AOT compilation with Powertools for .NET Logger, addressing performance, trimming, and deployment considerations.
8+
This tutorial shows you how to set up an AWS Lambda project using Native AOT compilation with Powertools for .NET
9+
Logger, addressing performance, trimming, and deployment considerations.
910

1011
## Prerequisites
1112

@@ -16,7 +17,8 @@ This tutorial shows you how to set up an AWS Lambda project using Native AOT com
1617

1718
## 1. Understanding Native AOT
1819

19-
Native AOT (Ahead-of-Time) compilation converts your .NET application directly to native code during build time rather than compiling to IL (Intermediate Language) code that gets JIT-compiled at runtime. Benefits for AWS Lambda include:
20+
Native AOT (Ahead-of-Time) compilation converts your .NET application directly to native code during build time rather
21+
than compiling to IL (Intermediate Language) code that gets JIT-compiled at runtime. Benefits for AWS Lambda include:
2022

2123
- Faster cold start times (typically 50-70% reduction)
2224
- Lower memory footprint
@@ -74,130 +76,114 @@ dotnet add package AWS.Lambda.Powertools.Logging
7476
Let's modify the Function.cs file to implement our function with Powertools Logger in an AOT-compatible way:
7577

7678
```csharp
77-
using System.Text.Json;
7879
using Amazon.Lambda.Core;
7980
using Amazon.Lambda.RuntimeSupport;
8081
using Amazon.Lambda.Serialization.SystemTextJson;
82+
using System.Text.Json.Serialization;
83+
using System.Text.Json;
8184
using AWS.Lambda.Powertools.Logging;
85+
using Microsoft.Extensions.Logging;
86+
8287

8388
namespace PowertoolsAotLoggerDemo;
8489

8590
public class Function
8691
{
87-
/// <summary>
88-
/// The main entry point for the Lambda function. The main function is called once during the Lambda init phase.
89-
/// It initializes the Lambda runtime client and passes the function handler to it.
90-
/// </summary>
92+
private static ILogger _logger;
93+
9194
private static async Task Main()
9295
{
93-
// Configure the serializer
94-
var serializer = new DefaultLambdaJsonSerializer(options =>
95-
{
96-
options.PropertyNameCaseInsensitive = true;
97-
});
98-
99-
// Create a runtime client and pass the handler function
100-
using var handlerWrapper = LambdaBootstrapBuilder.Create()
101-
.WithSerializer(serializer)
102-
.WithHandler(FunctionHandler)
103-
.Build();
104-
105-
// Start handling Lambda events
106-
await handlerWrapper.RunAsync();
96+
_logger = LoggerFactory.Create(builder =>
97+
{
98+
builder.AddPowertoolsLogger(config =>
99+
{
100+
config.Service = "TestService";
101+
config.LoggerOutputCase = LoggerOutputCase.PascalCase;
102+
config.JsonOptions = new JsonSerializerOptions
103+
{
104+
TypeInfoResolver = LambdaFunctionJsonSerializerContext.Default
105+
};
106+
});
107+
}).CreatePowertoolsLogger();
108+
109+
Func<string, ILambdaContext, string> handler = FunctionHandler;
110+
await LambdaBootstrapBuilder.Create(handler, new SourceGeneratorLambdaJsonSerializer<LambdaFunctionJsonSerializerContext>())
111+
.Build()
112+
.RunAsync();
107113
}
108114

109-
/// <summary>
110-
/// This function handler processes incoming events.
111-
/// </summary>
112-
[Logging(LoggerOutputCase = LoggerOutputCase.CamelCase, CorrelationIdPath = "/headers/x-correlation-id")]
113-
public static async Task<string> FunctionHandler(JsonElement input, ILambdaContext context)
115+
public static string FunctionHandler(string input, ILambdaContext context)
114116
{
115-
// Log the incoming event
116-
Logger.LogInformation("Processing event: {@Event}", input);
117-
118-
// Extract a name from the event (if provided)
119-
string name = "World";
120-
if (input.TryGetProperty("name", out var nameProperty) && nameProperty.ValueKind == JsonValueKind.String)
121-
{
122-
name = nameProperty.GetString() ?? "World";
123-
Logger.LogInformation("Name provided: {Name}", name);
124-
}
125-
else
126-
{
127-
Logger.LogInformation("Using default name");
128-
}
129-
130-
// Create a simple response
131-
var response = new
132-
{
133-
Message = $"Hello, {name}! (from Native AOT)",
134-
ProcessedAt = DateTime.UtcNow.ToString("o"),
135-
ExecutionEnvironment = "Native AOT"
136-
};
137-
138-
// Log the response
139-
Logger.LogInformation("Returning response: {@Response}", response);
140-
141-
// Return the serialized response
142-
return JsonSerializer.Serialize(response);
117+
_logger.LogInformation("Processing input: {Input}", input);
118+
_logger.LogInformation("Processing context: {@Context}", context);
119+
120+
return input.ToUpper();
143121
}
144122
}
123+
124+
125+
[JsonSerializable(typeof(string))]
126+
[JsonSerializable(typeof(ILambdaContext))] // make sure to include ILambdaContext for serialization
127+
public partial class LambdaFunctionJsonSerializerContext : JsonSerializerContext
128+
{
129+
}
145130
```
146131

147132
## 6. Updating the Project File for AOT Compatibility
148133

149-
150134
```xml
135+
151136
<Project Sdk="Microsoft.NET.Sdk">
152-
<PropertyGroup>
153-
<TargetFramework>net8.0</TargetFramework>
154-
<ImplicitUsings>enable</ImplicitUsings>
155-
<Nullable>enable</Nullable>
156-
157-
<!-- Enable AOT compilation -->
158-
<PublishAot>true</PublishAot>
159-
160-
<!-- Enable trimming, required for Native AOT -->
161-
<PublishTrimmed>true</PublishTrimmed>
162-
163-
<!-- Set trimming level: full is most aggressive -->
164-
<TrimMode>full</TrimMode>
165-
166-
<!-- Prevent warnings from becoming errors -->
167-
<TrimmerWarningLevel>0</TrimmerWarningLevel>
168-
169-
<!-- If you're encountering trimming issues, enable this for more detailed info -->
170-
<!-- <TrimmerLogLevel>detailed</TrimmerLogLevel> -->
171-
172-
<!-- These settings optimize for Lambda -->
173-
<StripSymbols>true</StripSymbols>
174-
<OptimizationPreference>Size</OptimizationPreference>
175-
<InvariantGlobalization>true</InvariantGlobalization>
176-
177-
<!-- Assembly attributes needed for Lambda -->
178-
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
179-
<AWSProjectType>Lambda</AWSProjectType>
180-
181-
<!-- Native AOT requires executable, not library -->
182-
<OutputType>Exe</OutputType>
183-
184-
<!-- Avoid the copious logging from the native AOT compiler -->
185-
<IlcGenerateStackTraceData>false</IlcGenerateStackTraceData>
186-
<IlcOptimizationPreference>Size</IlcOptimizationPreference>
187-
</PropertyGroup>
188-
189-
<ItemGroup>
190-
<PackageReference Include="Amazon.Lambda.RuntimeSupport" Version="1.10.0" />
191-
<PackageReference Include="Amazon.Lambda.Core" Version="2.2.0" />
192-
<PackageReference Include="Amazon.Lambda.Serialization.SystemTextJson" Version="2.4.0" />
193-
<PackageReference Include="AWS.Lambda.Powertools.Logging" Version="1.4.0" />
194-
</ItemGroup>
137+
<PropertyGroup>
138+
<TargetFramework>net8.0</TargetFramework>
139+
<ImplicitUsings>enable</ImplicitUsings>
140+
<Nullable>enable</Nullable>
141+
142+
<!-- Enable AOT compilation -->
143+
<PublishAot>true</PublishAot>
144+
145+
<!-- Enable trimming, required for Native AOT -->
146+
<PublishTrimmed>true</PublishTrimmed>
147+
148+
<!-- Set trimming level: full is most aggressive -->
149+
<TrimMode>full</TrimMode>
150+
151+
<!-- Prevent warnings from becoming errors -->
152+
<TrimmerWarningLevel>0</TrimmerWarningLevel>
153+
154+
<!-- If you're encountering trimming issues, enable this for more detailed info -->
155+
<!-- <TrimmerLogLevel>detailed</TrimmerLogLevel> -->
156+
157+
<!-- These settings optimize for Lambda -->
158+
<StripSymbols>true</StripSymbols>
159+
<OptimizationPreference>Size</OptimizationPreference>
160+
<InvariantGlobalization>true</InvariantGlobalization>
161+
162+
<!-- Assembly attributes needed for Lambda -->
163+
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
164+
<AWSProjectType>Lambda</AWSProjectType>
165+
166+
<!-- Native AOT requires executable, not library -->
167+
<OutputType>Exe</OutputType>
168+
169+
<!-- Avoid the copious logging from the native AOT compiler -->
170+
<IlcGenerateStackTraceData>false</IlcGenerateStackTraceData>
171+
<IlcOptimizationPreference>Size</IlcOptimizationPreference>
172+
</PropertyGroup>
173+
174+
<ItemGroup>
175+
<PackageReference Include="Amazon.Lambda.RuntimeSupport" Version="1.12.0"/>
176+
<PackageReference Include="Amazon.Lambda.Core" Version="2.5.0"/>
177+
<PackageReference Include="Amazon.Lambda.Serialization.SystemTextJson" Version="2.4.4"/>
178+
<PackageReference Include="AWS.Lambda.Powertools.Logging" Version="2.0.0"/>
179+
</ItemGroup>
195180
</Project>
196181
```
197182

198183
## 8. Cross-Platform Deployment Considerations
199184

200-
Native AOT compilation must target the same OS and architecture as the deployment environment. AWS Lambda runs on Amazon Linux 2023 (AL2023) with x64 architecture.
185+
Native AOT compilation must target the same OS and architecture as the deployment environment. AWS Lambda runs on Amazon
186+
Linux 2023 (AL2023) with x64 architecture.
201187

202188
### Building for AL2023 on Different Platforms
203189

@@ -210,6 +196,7 @@ dotnet lambda deploy-function --function-name powertools-aot-logger-demo --funct
210196
```
211197

212198
This will:
199+
213200
1. Detect your project is using Native AOT
214201
2. Use Docker behind the scenes to compile for Amazon Linux
215202
3. Deploy the resulting function
@@ -267,9 +254,42 @@ You should see a response like:
267254

268255
```json
269256
{
270-
"Message": "Hello, PowertoolsAOT! (from Native AOT)",
271-
"ProcessedAt": "2023-11-10T10:15:20.1234567Z",
272-
"ExecutionEnvironment": "Native AOT"
257+
"Level": "Information",
258+
"Message": "test",
259+
"Timestamp": "2025-05-06T09:52:19.8222787Z",
260+
"Service": "TestService",
261+
"ColdStart": true,
262+
"XrayTraceId": "1-6819dbd3-0de6dc4b6cc712b020ee8ae7",
263+
"Name": "AWS.Lambda.Powertools.Logging.Logger"
264+
}
265+
{
266+
"Level": "Information",
267+
"Message": "Processing context: Amazon.Lambda.RuntimeSupport.LambdaContext",
268+
"Timestamp": "2025-05-06T09:52:19.8232664Z",
269+
"Service": "TestService",
270+
"ColdStart": true,
271+
"XrayTraceId": "1-6819dbd3-0de6dc4b6cc712b020ee8ae7",
272+
"Name": "AWS.Lambda.Powertools.Logging.Logger",
273+
"Context": {
274+
"AwsRequestId": "20f8da57-002b-426d-84c2-c295e4797e23",
275+
"ClientContext": {
276+
"Environment": null,
277+
"Client": null,
278+
"Custom": null
279+
},
280+
"FunctionName": "powertools-aot-logger-demo",
281+
"FunctionVersion": "$LATEST",
282+
"Identity": {
283+
"IdentityId": null,
284+
"IdentityPoolId": null
285+
},
286+
"InvokedFunctionArn": "your arn",
287+
"Logger": {},
288+
"LogGroupName": "/aws/lambda/powertools-aot-logger-demo",
289+
"LogStreamName": "2025/05/06/[$LATEST]71249d02013b42b9b044b42dd4c7c37a",
290+
"MemoryLimitInMB": 512,
291+
"RemainingTime": "00:00:29.9972216"
292+
}
273293
}
274294
```
275295

@@ -279,7 +299,8 @@ Check the logs in CloudWatch Logs to see the structured logs created by Powertoo
279299

280300
### Trimming Considerations
281301

282-
Native AOT uses aggressive trimming, which can cause issues with reflection-based code. Here are tips to avoid common problems:
302+
Native AOT uses aggressive trimming, which can cause issues with reflection-based code. Here are tips to avoid common
303+
problems:
283304

284305
1. **Using DynamicJsonSerializer**: If you're encountering trimming issues with JSON serialization, add a trimming hint:
285306

@@ -291,7 +312,8 @@ public class MyRequestType
291312
}
292313
```
293314

294-
2. **Logging Objects**: When logging objects with structural logging, consider creating simple DTOs instead of complex types:
315+
2. **Logging Objects**: When logging objects with structural logging, consider creating simple DTOs instead of complex
316+
types:
295317

296318
```csharp
297319
// Instead of logging complex domain objects:
@@ -305,18 +327,20 @@ Logger.LogInformation("User: {@userInfo}", userInfo);
305327
3. **Handling Reflection**: If you need reflection, explicitly preserve types:
306328

307329
```xml
330+
308331
<ItemGroup>
309-
<TrimmerRootDescriptor Include="TrimmerRoots.xml" />
332+
<TrimmerRootDescriptor Include="TrimmerRoots.xml"/>
310333
</ItemGroup>
311334
```
312335

313336
And in TrimmerRoots.xml:
314337

315338
```xml
339+
316340
<linker>
317-
<assembly fullname="YourAssembly">
318-
<type fullname="YourAssembly.TypeToPreserve" preserve="all" />
319-
</assembly>
341+
<assembly fullname="YourAssembly">
342+
<type fullname="YourAssembly.TypeToPreserve" preserve="all"/>
343+
</assembly>
320344
</linker>
321345
```
322346

@@ -341,11 +365,13 @@ aws lambda update-function-configuration \
341365
3. **ARM64 Support**: For even better performance, consider using ARM64 architecture:
342366

343367
When creating your project:
368+
344369
```bash
345370
dotnet new lambda.NativeAOT -n PowertoolsAotLoggerDemo --architecture arm64
346371
```
347372

348373
Or modify your deployment:
374+
349375
```bash
350376
aws lambda update-function-configuration \
351377
--function-name powertools-aot-logger-demo \
@@ -370,16 +396,18 @@ fields @timestamp, coldStart, billedDurationMs, maxMemoryUsedMB
370396
If you see errors about missing metadata, you may need to add more types to your trimmer roots:
371397

372398
```xml
399+
373400
<ItemGroup>
374-
<TrimmerRootAssembly Include="AWS.Lambda.Powertools.Logging" />
375-
<TrimmerRootAssembly Include="System.Private.CoreLib" />
376-
<TrimmerRootAssembly Include="System.Text.Json" />
401+
<TrimmerRootAssembly Include="AWS.Lambda.Powertools.Logging"/>
402+
<TrimmerRootAssembly Include="System.Private.CoreLib"/>
403+
<TrimmerRootAssembly Include="System.Text.Json"/>
377404
</ItemGroup>
378405
```
379406

380407
### Build Failures on macOS/Windows
381408

382-
If you're building directly on macOS/Windows without Docker and encountering errors, remember that Native AOT is platform-specific. Always use the cross-platform build options mentioned earlier.
409+
If you're building directly on macOS/Windows without Docker and encountering errors, remember that Native AOT is
410+
platform-specific. Always use the cross-platform build options mentioned earlier.
383411

384412
## Summary
385413

@@ -390,7 +418,9 @@ In this tutorial, you've learned:
390418
3. Cross-platform build and deployment strategies for Amazon Linux 2023
391419
4. Performance optimization techniques specific to AOT lambdas
392420

393-
Native AOT combined with Powertools Logger gives you the best of both worlds: high-performance, low-latency Lambda functions with rich, structured logging capabilities.
421+
Native AOT combined with Powertools Logger gives you the best of both worlds: high-performance, low-latency Lambda
422+
functions with rich, structured logging capabilities.
394423

395424
!!! tip "Next Steps"
396-
Explore using the Embedded Metrics Format (EMF) with your Native AOT Lambda functions for enhanced observability, or try implementing Powertools Tracing in your Native AOT functions.
425+
Explore using the Embedded Metrics Format (EMF) with your Native AOT Lambda functions for enhanced observability, or try
426+
implementing Powertools Tracing in your Native AOT functions.

mkdocs.yml

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,6 @@ nav:
1818
- getting-started/logger/simple.md
1919
- getting-started/logger/aspnet.md
2020
- getting-started/logger/aot.md
21-
- Metrics:
22-
- getting-started/metrics/simple.md
23-
- getting-started/metrics/aspnet.md
24-
- getting-started/metrics/aot.md
25-
- Tracing:
26-
- getting-started/tracing/simple.md
27-
- getting-started/tracing/aot.md
28-
- Idempotency:
29-
- getting-started/idempotency/simple.md
30-
- getting-started/idempotency/aot.md
3121
- Features:
3222
- core/logging.md
3323
- core/metrics.md

0 commit comments

Comments
 (0)