| title | Logging |
|---|---|
| description | Core utility |
The logging utility provides a Lambda optimized logger with output structured as JSON.
- Capture key fields from Lambda context, cold start and structures logging output as JSON
- Log Lambda event when instructed (disabled by default)
- Log sampling enables DEBUG log level for a percentage of requests (disabled by default)
- Append additional keys to structured log at any point in time
- Ahead-of-Time compilation to native code support AOT
- Custom log formatter to override default log structure
- Support for AWS Lambda Advanced Logging Controls (ALC) {target="_blank"}
- Support for Microsoft.Extensions.Logging and ILogger interface
- Support for ILoggerFactory interface
- Support for message templates
{}and{@}for structured logging
!!! warning "Migrating to v3"
If you're upgrading to v3, please review the [Migration Guide v3](../migration-guide-v3.md) for important breaking changes including .NET 8 requirement and AWS SDK v4 migration.
Powertools for AWS Lambda (.NET) are available as NuGet packages. You can install the packages
from NuGet Gallery{target="_blank"} or from Visual Studio
editor by searching AWS.Lambda.Powertools* to see various utilities available.
-
AWS.Lambda.Powertools.Logging:
dotnet add package AWS.Lambda.Powertools.Logging
!!! info
AOT Support
If loooking for AOT specific configurations navigate to the [AOT section](#aot-support)
Logging requires two settings:
| Setting | Description | Environment variable | Attribute parameter |
|---|---|---|---|
| Service | Sets Service key that will be present across all log statements | POWERTOOLS_SERVICE_NAME |
Service |
| Logging level | Sets how verbose Logger should be (Information, by default) | POWERTOOLS_LOG_LEVEL |
LogLevel |
| Environment variable | Description | Default |
|---|---|---|
| POWERTOOLS_SERVICE_NAME | Sets service name used for tracing namespace, metrics dimension and structured logging | "service_undefined" |
| POWERTOOLS_LOG_LEVEL | Sets logging level | Information |
| POWERTOOLS_LOGGER_CASE | Override the default casing for log keys | SnakeCase |
| POWERTOOLS_LOGGER_LOG_EVENT | Logs incoming event | false |
| POWERTOOLS_LOGGER_SAMPLE_RATE | Debug log sampling | 0 |
You can set up the logger in different ways. The most common way is to use the Logging attribute on your Lambda.
You can also use the ILogger interface to log messages. This interface is part of the Microsoft.Extensions.Logging.
=== "Using decorator"
```csharp hl_lines="6 10"
--8<-- "docs/snippets/logging/GettingStarted.cs:using_decorator"
```
=== "Logger Factory"
```csharp hl_lines="6 10-17 23"
--8<-- "docs/snippets/logging/GettingStarted.cs:logger_factory"
```
=== "With Builder"
```csharp hl_lines="6 10-13 19"
--8<-- "docs/snippets/logging/GettingStarted.cs:with_builder"
```
You can customize the logger by setting the following properties in the Logger.Configure method:
| Property | Description |
|---|---|
Service |
The name of the service. This is used to identify the service in the logs. |
MinimumLogLevel |
The minimum log level to log. This is used to filter out logs below the specified level. |
LogFormatter |
The log formatter to use. This is used to customize the structure of the log entries. |
JsonOptions |
The JSON options to use. This is used to customize the serialization of logs. |
LogBuffering |
The log buffering options. This is used to configure log buffering. |
TimestampFormat |
The format of the timestamp. This is used to customize the format of the timestamp in the logs. |
SamplingRate |
Sets a percentage (0.0 to 1.0) of logs that will be dynamically elevated to DEBUG level |
LoggerOutputCase |
The output casing of the logger. This is used to customize the casing of the log entries. |
LogOutput |
Specifies the console output wrapper used for writing logs. This property allows redirecting log output for testing or specialized handling scenarios. |
You can configure Powertools Logger using the static Logger class. This class is a singleton and is created when the
Lambda function is initialized. You can configure the logger using the Logger.Configure method.
=== "Configure static Logger"
```csharp hl_lines="5-9"
--8<-- "docs/snippets/logging/Configuration.cs:configure_static_logger"
```
You can also use the ILogger interface to log messages. This interface is part of the Microsoft.Extensions.Logging.
With this approach you get more flexibility and testability using dependency injection (DI).
=== "Configure with LoggerFactory or Builder"
```csharp hl_lines="5-12"
--8<-- "docs/snippets/logging/Configuration.cs:configure_ilogger"
```
Your logs will always include the following keys to your structured logging:
| Key | Type | Example | Description |
|---|---|---|---|
| Level | string | "Information" | Logging level |
| Message | string | "Collecting payment" | Log statement value. Unserializable JSON values will be cast to string |
| Timestamp | string | "2020-05-24 18:17:33,774" | Timestamp of actual log statement |
| Service | string | "payment" | Service name defined. "service_undefined" will be used if unknown |
| ColdStart | bool | true | ColdStart value. |
| FunctionName | string | "example-powertools-HelloWorldFunction-1P1Z6B39FLU73" | |
| FunctionMemorySize | string | "128" | |
| FunctionArn | string | "arn:aws:lambda:eu-west-1:012345678910:function:example-powertools-HelloWorldFunction-1P1Z6B39FLU73" | |
| FunctionRequestId | string | "899856cb-83d1-40d7-8611-9e78f15f32f4" | AWS Request ID from lambda context |
| FunctionVersion | string | "12" | |
| XRayTraceId | string | "1-5759e988-bd862e3fe1be46a994272793" | X-Ray Trace ID when Lambda function has enabled Tracing |
| Name | string | "Powertools for AWS Lambda (.NET) Logger" | Logger name |
| SamplingRate | int | 0.1 | Debug logging sampling rate in percentage e.g. 10% in this case |
| Customer Keys |
!!! Warning
If you emit a log message with a key that matches one of level, message, name, service, or timestamp, the Logger will ignore the key.
You can use message templates to extract properties from your objects and log them as structured data.
!!! info
Override the `ToString()` method of your object to return a meaningful string representation of the object.
This is especially important when using `{}` to log the object as a string.
```csharp
--8<-- "docs/snippets/logging/MessageTemplates.cs:tostring_override"
```
If you want to log the object as a JSON object, use {@}. This will serialize the object and log it as a JSON object.
=== "Message template {@}"
```csharp hl_lines="7-14"
--8<-- "docs/snippets/logging/MessageTemplates.cs:message_template_at"
```
=== "{@} Output"
```json hl_lines="3 8-12"
{
"level": "Information",
"message": "User object: Doe, John (42)",
"timestamp": "2025-04-07 09:06:30.708",
"service": "user-service",
"coldStart": true,
"name": "AWS.Lambda.Powertools.Logging.Logger",
"user": {
"firstName": "John",
"lastName": "Doe",
"age": 42
},
...
}
```
If you want to log the object as a string, use {}. This will call the ToString() method of the object and log it as
a string.
=== "Message template {} ToString"
```csharp hl_lines="7-12 14 18 19"
--8<-- "docs/snippets/logging/MessageTemplates.cs:message_template_tostring"
```
=== "Output {} ToString"
```json hl_lines="3 8 12 17 21 26"
{
"level": "Information",
"message": "User data: Doe, John (42)",
"timestamp": "2025-04-07 09:06:30.689",
"service": "user-servoice",
"coldStart": true,
"name": "AWS.Lambda.Powertools.Logging.Logger",
"user": "Doe, John (42)"
}
{
"level": "Information",
"message": "Price: 123.46",
"timestamp": "2025-04-07 09:23:01.235",
"service": "user-servoice",
"cold_start": true,
"name": "AWS.Lambda.Powertools.Logging.Logger",
"price": 123.46
}
{
"level": "Information",
"message": "Percentage: 12.3%",
"timestamp": "2025-04-07 09:23:01.260",
"service": "user-servoice",
"cold_start": true,
"name": "AWS.Lambda.Powertools.Logging.Logger",
"percent": "12.3%"
}
```
When debugging in non-production environments, you can instruct Logger to log the incoming event with LogEvent
parameter or via POWERTOOLS_LOGGER_LOG_EVENT environment variable.
!!! warning Log event is disabled by default to prevent sensitive info being logged.
=== "Function.cs"
```csharp hl_lines="6"
--8<-- "docs/snippets/logging/LoggingEvent.cs:log_event"
```
You can set a Correlation ID using CorrelationIdPath parameter by passing
a JSON Pointer expression{target="_blank"}.
!!! Attention
The JSON Pointer expression is case sensitive. In the bellow example /headers/my_request_id_header would work but
/Headers/my_request_id_header would not find the element.
=== "Function.cs"
```csharp hl_lines="6"
--8<-- "docs/snippets/logging/CorrelationId.cs:correlation_id_custom"
```
=== "Example Event"
```json hl_lines="3"
{
"headers": {
"my_request_id_header": "correlation_id_value"
}
}
```
=== "Example CloudWatch Logs excerpt"
```json hl_lines="15"
{
"level": "Information",
"message": "Collecting payment",
"timestamp": "2021-12-13T20:32:22.5774262Z",
"service": "lambda-example",
"cold_start": true,
"function_name": "test",
"function_memory_size": 128,
"function_arn": "arn:aws:lambda:eu-west-1:12345678910:function:test",
"function_request_id": "52fdfc07-2182-154f-163f-5f0f9a621d72",
"function_version": "$LATEST",
"xray_trace_id": "1-61b7add4-66532bb81441e1b060389429",
"name": "AWS.Lambda.Powertools.Logging.Logger",
"sampling_rate": 0.7,
"correlation_id": "correlation_id_value",
}
```
We provide built-in JSON Pointer expression {target="_blank"} for known event sources, where either a request ID or X-Ray Trace ID are present.
=== "Function.cs"
```csharp hl_lines="6"
--8<-- "docs/snippets/logging/CorrelationId.cs:correlation_id_builtin"
```
=== "Example Event"
```json hl_lines="3"
{
"RequestContext": {
"RequestId": "correlation_id_value"
}
}
```
=== "Example CloudWatch Logs excerpt"
```json hl_lines="15"
{
"level": "Information",
"message": "Collecting payment",
"timestamp": "2021-12-13T20:32:22.5774262Z",
"service": "lambda-example",
"cold_start": true,
"function_name": "test",
"function_memory_size": 128,
"function_arn": "arn:aws:lambda:eu-west-1:12345678910:function:test",
"function_request_id": "52fdfc07-2182-154f-163f-5f0f9a621d72",
"function_version": "$LATEST",
"xray_trace_id": "1-61b7add4-66532bb81441e1b060389429",
"name": "AWS.Lambda.Powertools.Logging.Logger",
"sampling_rate": 0.7,
"correlation_id": "correlation_id_value",
}
```
!!! info "Custom keys are persisted across warm invocations"
Always set additional keys as part of your handler to ensure they have the latest value, or explicitly clear them with
ClearState=true.
You can append your own keys to your existing logs via AppendKey. Typically this value would be passed into the
function via the event. Appended keys are added to all subsequent log entries in the current execution from the point
the logger method is called. To ensure the key is added to all log entries, call this method as early as possible in the
Lambda handler.
=== "Function.cs"
```csharp hl_lines="21"
--8<-- "docs/snippets/logging/AppendingKeys.cs:append_keys"
```
=== "Example CloudWatch Logs excerpt"
```json hl_lines="4 5 6"
{
"level": "Information",
"message": "Getting ip address from external service"
"timestamp": "2022-03-14T07:25:20.9418065Z",
"service": "powertools-dotnet-logging-sample",
"cold_start": false,
"function_name": "PowertoolsLoggingSample-HelloWorldFunction-hm1r10VT3lCy",
"function_memory_size": 256,
"function_arn": "arn:aws:lambda:function:PowertoolsLoggingSample-HelloWorldFunction-hm1r10VT3lCy",
"function_request_id": "96570b2c-f00e-471c-94ad-b25e95ba7347",
"function_version": "$LATEST",
"xray_trace_id": "1-622eede0-647960c56a91f3b071a9fff1",
"name": "AWS.Lambda.Powertools.Logging.Logger",
"lookup_info": {
"lookup_id": "4c50eace-8b1e-43d3-92ba-0efacf5d1625"
},
}
```
You can remove any additional key from entry using Logger.RemoveKeys().
=== "Function.cs"
```csharp hl_lines="21 22"
--8<-- "docs/snippets/logging/AppendingKeys.cs:remove_keys"
```
The ExtraKeys method allows temporary modification of the Logger's context without manual cleanup. It's useful for adding context keys to specific workflows while maintaining the logger's overall state.
Keys are automatically removed when the scope ends, eliminating the need to manually call AppendKey and RemoveKeys.
=== "Using Dictionary"
```csharp hl_lines="12-16"
--8<-- "docs/snippets/logging/ExtraKeys.cs:extra_keys_dictionary"
```
=== "Using Tuples"
```csharp hl_lines="12-16"
--8<-- "docs/snippets/logging/ExtraKeys.cs:extra_keys_tuples"
```
=== "Nested Scopes"
```csharp hl_lines="10-19"
--8<-- "docs/snippets/logging/ExtraKeys.cs:extra_keys_nested"
```
=== "Example CloudWatch Logs excerpt"
```json hl_lines="14 15"
{
"level": "Information",
"message": "Processing order",
"timestamp": "2024-01-15T10:30:00.0000000Z",
"service": "order-service",
"cold_start": true,
"function_name": "OrderProcessor",
"function_memory_size": 256,
"function_arn": "arn:aws:lambda:eu-west-1:123456789:function:OrderProcessor",
"function_request_id": "abc-123-def",
"function_version": "$LATEST",
"xray_trace_id": "1-abc-123",
"name": "AWS.Lambda.Powertools.Logging.Logger",
"order_id": "order-456",
"customer_id": "customer-123"
}
```
!!! tip "When to use ExtraKeys vs AppendKey"
Use ExtraKeys when you need keys for a specific operation or code block. Use AppendKey when keys should persist for the entire Lambda invocation.
!!! warning "Key overwrite behavior"
If a key already exists when entering an ExtraKeys scope, it will be overwritten and then removed when the scope ends. The original value is not restored. Use unique key names within ExtraKeys scopes to avoid unexpected behavior.
!!! info "Async safe"
ExtraKeys is safe to use across async/await boundaries. Keys will correctly flow through asynchronous operations within the same execution context.
Extra keys can also be added to a single log entry using message templates. Unlike AppendKey or ExtraKeys(), these keys will only apply to the current log entry.
Extra keys argument is available for all log levels' methods, as implemented in the standard logging library - e.g. Logger.Information, Logger.Warning.
It accepts any dictionary, and all keyword arguments will be added as part of the root structure of the logs for that log statement.
!!! info Any keyword argument added using extra keys will not be persisted for subsequent messages.
=== "Function.cs"
```csharp hl_lines="16"
--8<-- "docs/snippets/logging/ExtraKeys.cs:extra_keys_single_entry"
```
Logger is commonly initialized in the global scope. Due
to Lambda Execution Context reuse, this means that
custom keys can be persisted across invocations. If you want all custom keys to be deleted, you can use
ClearState=true attribute on [Logging] attribute.
=== "Function.cs"
```csharp hl_lines="6 13"
--8<-- "docs/snippets/logging/ClearState.cs:clear_state"
```
=== "#1 Request"
```json hl_lines="11"
{
"level": "Information",
"message": "Collecting payment",
"timestamp": "2021-12-13T20:32:22.5774262Z",
"service": "payment",
"cold_start": true,
"function_name": "test",
"function_memory_size": 128,
"function_arn": "arn:aws:lambda:eu-west-1:12345678910:function:test",
"function_request_id": "52fdfc07-2182-154f-163f-5f0f9a621d72",
"special_key": "value"
}
```
=== "#2 Request"
```json
{
"level": "Information",
"message": "Collecting payment",
"timestamp": "2021-12-13T20:32:22.5774262Z",
"service": "payment",
"cold_start": true,
"function_name": "test",
"function_memory_size": 128,
"function_arn": "arn:aws:lambda:eu-west-1:12345678910:function:test",
"function_request_id": "52fdfc07-2182-154f-163f-5f0f9a621d72"
}
```
Use sampling when you want to dynamically change your log level to DEBUG based on a percentage of the Lambda function invocations.
You can use values ranging from 0.0 to 1 (100%) when setting POWERTOOLS_LOGGER_SAMPLE_RATE env var, or SamplingRate parameter in Logger.
???+ tip "Tip: When is this useful?" Log sampling allows you to capture debug information for a fraction of your requests, helping you diagnose rare or intermittent issues without increasing the overall verbosity of your logs.
Example: Imagine an e-commerce checkout process where you want to understand rare payment gateway errors. With 10% sampling, you'll log detailed information for a small subset of transactions, making troubleshooting easier without generating excessive logs.
The sampling decision happens automatically with each invocation when using Logger decorator. When not using the decorator, you're in charge of refreshing it via RefreshSampleRateCalculation method. Skipping both may lead to unexpected sampling results.
=== "Sampling via attribute parameter"
```csharp hl_lines="6"
--8<-- "docs/snippets/logging/SamplingDebugLogs.cs:sampling_attribute"
```
=== "Sampling Logger.Configure"
```csharp hl_lines="5-10 16"
--8<-- "docs/snippets/logging/SamplingDebugLogs.cs:sampling_configure"
```
=== "Sampling via environment variable"
```yaml hl_lines="8"
Resources:
HelloWorldFunction:
Type: AWS::Serverless::Function
Properties:
...
Environment:
Variables:
POWERTOOLS_LOGGER_SAMPLE_RATE: 0.5
```
By definition Powertools for AWS Lambda (.NET) outputs logging keys using snake case (e.g. "function_memory_size": 128). This allows developers using different Powertools for AWS Lambda (.NET) runtimes, to search logs across services written in languages such as Python or TypeScript.
If you want to override the default behavior you can either set the desired casing through attributes, as described in
the example below, or by setting the POWERTOOLS_LOGGER_CASE environment variable on your AWS Lambda function. Allowed
values are: CamelCase, PascalCase and SnakeCase.
=== "Output casing via attribute parameter"
```csharp hl_lines="6"
--8<-- "docs/snippets/logging/OutputCasing.cs:output_casing_attribute"
```
Below are some output examples for different casing.
=== "Camel Case"
```json
{
"level": "Information",
"message": "Collecting payment",
"timestamp": "2021-12-13T20:32:22.5774262Z",
"service": "payment",
"coldStart": true,
"functionName": "test",
"functionMemorySize": 128,
"functionArn": "arn:aws:lambda:eu-west-1:12345678910:function:test",
"functionRequestId": "52fdfc07-2182-154f-163f-5f0f9a621d72"
}
```
=== "Pascal Case"
```json
{
"Level": "Information",
"Message": "Collecting payment",
"Timestamp": "2021-12-13T20:32:22.5774262Z",
"Service": "payment",
"ColdStart": true,
"FunctionName": "test",
"FunctionMemorySize": 128,
"FunctionArn": "arn:aws:lambda:eu-west-1:12345678910:function:test",
"FunctionRequestId": "52fdfc07-2182-154f-163f-5f0f9a621d72"
}
```
=== "Snake Case"
```json
{
"level": "Information",
"message": "Collecting payment",
"timestamp": "2021-12-13T20:32:22.5774262Z",
"service": "payment",
"cold_start": true,
"function_name": "test",
"function_memory_size": 128,
"function_arn": "arn:aws:lambda:eu-west-1:12345678910:function:test",
"function_request_id": "52fdfc07-2182-154f-163f-5f0f9a621d72"
}
```
The default log level is Information and can be set using the MinimumLogLevel property option or by using the POWERTOOLS_LOG_LEVEL environment variable.
We support the following log levels:
| Level | Numeric value | Lambda Level |
|---|---|---|
Trace |
0 | trace |
Debug |
1 | debug |
Information |
2 | info |
Warning |
3 | warn |
Error |
4 | error |
Critical |
5 | fatal |
None |
6 |
!!! question "When is it useful?" When you want to set a logging policy to drop informational or verbose logs for one or all AWS Lambda functions, regardless of runtime and logger used.
With AWS Lambda Advanced Logging Controls (ALC) {target="_blank"}, you can enforce a minimum log level that Lambda will accept from your application code.
When enabled, you should keep Logger and ALC log level in sync to avoid data loss.
!!! warning "When using AWS Lambda Advanced Logging Controls (ALC)"
- When Powertools Logger output is set to PascalCase Level property name will be replaced by LogLevel as
a property name.
- ALC takes precedence over POWERTOOLS_LOG_LEVEL and when setting it in code using [Logging(LogLevel = )]
Here's a sequence diagram to demonstrate how ALC will drop both Information and Debug logs emitted from Logger,
when ALC log level is stricter than Logger.
sequenceDiagram
title Lambda ALC allows WARN logs only
participant Lambda service
participant Lambda function
participant Application Logger
Note over Lambda service: AWS_LAMBDA_LOG_LEVEL="WARN"
Note over Application Logger: POWERTOOLS_LOG_LEVEL="DEBUG"
Lambda service->>Lambda function: Invoke (event)
Lambda function->>Lambda function: Calls handler
Lambda function->>Application Logger: Logger.Warning("Something happened")
Lambda function-->>Application Logger: Logger.Debug("Something happened")
Lambda function-->>Application Logger: Logger.Information("Something happened")
Lambda service->>Lambda service: DROP INFO and DEBUG logs
Lambda service->>CloudWatch Logs: Ingest error logs
Priority of log level settings in Powertools for AWS Lambda
We prioritise log level settings in this order:
- AWS_LAMBDA_LOG_LEVEL environment variable
- Setting the log level in code using
[Logging(LogLevel = )] - POWERTOOLS_LOG_LEVEL environment variable
If you set Logger level lower than ALC, we will emit a warning informing you that your messages will be discarded by
Lambda.
NOTE With ALC enabled, we are unable to increase the minimum log level below the
AWS_LAMBDA_LOG_LEVELenvironment variable value, see AWS Lambda service documentation {target="_blank"} for more details.
Powertools supports customizing the serialization and deserialization of Lambda JSON events and your own types using
JsonSerializerOptions.
You can do this by creating a custom JsonSerializerOptions and passing it to the JsonOptions of the Powertools
Logger.
Supports TypeInfoResolver and DictionaryKeyPolicy options. These two options are the most common ones used to
customize the serialization of Powertools Logger.
TypeInfoResolver: This option allows you to specify a customJsonSerializerContextthat contains the types you want to serialize and deserialize. This is especially useful when using AOT compilation, as it allows you to specify the types that should be included in the generated assembly.DictionaryKeyPolicy: This option allows you to specify a custom naming policy for the properties in the JSON output. This is useful when you want to change the casing of the property names or use a different naming convention.
!!! info
If you want to preserve the original casing of the property names (keys), you can set the DictionaryKeyPolicy to
null.
--8<-- "docs/snippets/logging/AdvancedConfiguration.cs:json_serializer_options"!!! warning
When using builder.Logging.AddPowertoolsLogger method it will use any already configured logging providers (file loggers, database loggers, third-party providers).
If you want to use Powertools Logger as the only logging provider, you should call `builder.Logging.ClearProviders()` before adding Powertools Logger or the new method override
```csharp
--8<-- "docs/snippets/logging/AdvancedConfiguration.cs:clear_providers"
```
You can customize the structure (keys and values) of your log entries by implementing a custom log formatter and
override default log formatter using LogFormatter property in the configure options.
You can implement a custom log formatter by
inheriting the ILogFormatter class and implementing the object FormatLogEntry(LogEntry logEntry) method.
=== "Function.cs"
```csharp hl_lines="11"
--8<-- "docs/snippets/logging/CustomLogFormatter.cs:custom_log_formatter_function"
```
=== "CustomLogFormatter.cs"
```csharp
--8<-- "docs/snippets/logging/CustomLogFormatter.cs:custom_log_formatter_class"
```
=== "Example CloudWatch Logs excerpt"
```json
{
"Message": "Test Message",
"Service": "lambda-example",
"CorrelationIds": {
"AwsRequestId": "52fdfc07-2182-154f-163f-5f0f9a621d72",
"XRayTraceId": "1-61b7add4-66532bb81441e1b060389429",
"CorrelationId": "correlation_id_value"
},
"LambdaFunction": {
"Name": "test",
"Arn": "arn:aws:lambda:eu-west-1:12345678910:function:test",
"MemorySize": 128,
"Version": "$LATEST",
"ColdStart": true
},
"Level": "Information",
"Timestamp": "2021-12-13T20:32:22.5774262Z",
"Logger": {
"Name": "AWS.Lambda.Powertools.Logging.Logger",
"SampleRate": 0.7
}
}
```
Log buffering enables you to buffer logs for a specific request or invocation. Enable log buffering by setting LogBuffering.Enabled = true when configuring a Logger instance. You can buffer logs at the Warning, Information, Debug or Trace level, and flush them automatically on error or manually as needed.
!!! tip "This is useful when you want to reduce the number of log messages emitted while still having detailed logs when needed, such as when troubleshooting issues."
=== "LogBufferingOptions"
```csharp hl_lines="5-12"
--8<-- "docs/snippets/logging/LogBuffering.cs:buffering_options"
```
When configuring the buffer, you can set the following options to fine-tune how logs are captured, stored, and emitted. You can configure the following options in the LogBuffering property:
| Parameter | Description | Configuration | Default |
|---|---|---|---|
Enabled |
Enable or disable log buffering | True, False |
False |
MaxBytes |
Maximum size of the log buffer in bytes | number |
20480 |
BufferAtLogLevel |
Minimum log level to buffer | Trace, Debug, Information, Warning |
Debug |
FlushOnErrorLog |
Automatically flush buffer when logging an error | True, False |
True |
=== "BufferAtLogLevel"
```csharp hl_lines="10 11"
--8<-- "docs/snippets/logging/LogBuffering.cs:buffer_at_log_level"
```
1. Setting `BufferAtLogLevel: 'Warning'` configures log buffering for `Warning` and all lower severity levels like `Information`, `Debug`, and `Trace`.
2. Calling `Logger.ClearBuffer()` will clear the buffer without emitting the logs.
=== "FlushOnErrorLog"
```csharp hl_lines="10 11"
--8<-- "docs/snippets/logging/LogBuffering.cs:flush_on_error_log"
```
1. Disabling `FlushOnErrorLog` will not flush the buffer when logging an error. This is useful when you want to control when the buffer is flushed by calling the `Logger.FlushBuffer()` method.
When using the Logger decorator, you can configure the logger to automatically flush the buffer when an error occurs. This is done by setting the FlushBufferOnUncaughtError option to true in the decorator.
=== "FlushBufferOnUncaughtError"
```csharp hl_lines="14"
--8<-- "docs/snippets/logging/LogBuffering.cs:flush_buffer_on_uncaught_error"
```
This works only when using the Logger decorator. You can configure the logger to automatically flush the buffer when an error occurs by setting the FlushBufferOnUncaughtError option to true in the decorator.
-
Does the buffer persist across Lambda invocations? No, each Lambda invocation has its own buffer. The buffer is initialized when the Lambda function is invoked and is cleared after the function execution completes or when flushed manually.
-
Are my logs buffered during cold starts? No, we never buffer logs during cold starts. This is because we want to ensure that logs emitted during this phase are always available for debugging and monitoring purposes. The buffer is only used during the execution of the Lambda function.
-
How can I prevent log buffering from consuming excessive memory? You can limit the size of the buffer by setting the
MaxBytesoption in theLogBufferingproperty. This will ensure that the buffer does not grow indefinitely and consume excessive memory. -
What happens if the log buffer reaches its maximum size? Older logs are removed from the buffer to make room for new logs. This means that if the buffer is full, you may lose some logs if they are not flushed before the buffer reaches its maximum size. When this happens, we emit a warning when flushing the buffer to indicate that some logs have been dropped.
-
How is the log size of a log line calculated? The log size is calculated based on the size of the serialized log line in bytes. This includes the size of the log message, the size of any additional keys, and the size of the timestamp.
-
What timestamp is used when I flush the logs? The timestamp preserves the original time when the log record was created. If you create a log record at 11:00:10 and flush it at 11:00:25, the log line will retain its original timestamp of 11:00:10.
-
What happens if I try to add a log line that is bigger than max buffer size? The log will be emitted directly to standard output and not buffered. When this happens, we emit a warning to indicate that the log line was too big to be buffered.
-
What happens if Lambda times out without flushing the buffer? Logs that are still in the buffer will be lost. If you are using the log buffer to log asynchronously, you should ensure that the buffer is flushed before the Lambda function times out. You can do this by calling the
Logger.FlushBuffer()method at the end of your Lambda function.
You can customize the timestamp format by setting the TimestampFormat property in the Logger.Configure method. The default format is o, which is the ISO 8601 format.
You can use any valid DateTime format string to customize the timestamp format.
For example, to use the yyyy-MM-dd HH:mm:ss format, you can do the following:
--8<-- "docs/snippets/logging/TimestampFormatting.cs:timestamp_formatting"This will output the timestamp in the following format:
{
"level": "Information",
"message": "Test Message",
"timestamp": "2021-12-13 20:32:22",
"service": "lambda-example",
...
}!!! info
If you want to use the `LogEvent`, `Custom Log Formatter` features, or serialize your own types when Logging events, you need to either pass `JsonSerializerContext` or make changes in your Lambda `Main` method.
!!! info
Starting from version 1.6.0, it is required to update the Amazon.Lambda.Serialization.SystemTextJson NuGet package to version 2.4.3 in your csproj.
To be able to serializer your own types, you need to pass your JsonSerializerContext to the TypeInfoResolver of the Logger.Configure method.
--8<-- "docs/snippets/logging/AotSupport.cs:json_serializer_options_aot"Replace SourceGeneratorLambdaJsonSerializer with PowertoolsSourceGeneratorSerializer.
This change enables Powertools to construct an instance of JsonSerializerOptions used to customize the serialization
and deserialization of Lambda JSON events and your own types.
=== "Before"
```csharp
--8<-- "docs/snippets/logging/AotSupport.cs:before_aot"
```
=== "After"
```csharp hl_lines="2"
--8<-- "docs/snippets/logging/AotSupport.cs:after_aot"
```
For example when you have your own Demo type
--8<-- "docs/snippets/logging/AotSupport.cs:demo_class"To be able to serialize it in AOT you have to have your own JsonSerializerContext
--8<-- "docs/snippets/logging/AotSupport.cs:json_serializer_context"When you update your code to use PowertoolsSourceGeneratorSerializer<MyCustomJsonSerializerContext>, we combine your
JsonSerializerContext with Powertools' JsonSerializerContext. This allows Powertools to serialize your types and
Lambda events.
To use a custom log formatter with AOT, pass an instance of ILogFormatter to PowertoolsSourceGeneratorSerializer
instead of using the static Logger.UseFormatter in the Function constructor as you do in non-AOT Lambdas.
=== "Function Main method"
```csharp hl_lines="5"
--8<-- "docs/snippets/logging/AotSupport.cs:custom_log_formatter_aot_function"
```
=== "CustomLogFormatter.cs"
```csharp
--8<-- "docs/snippets/logging/AotSupport.cs:custom_log_formatter_aot_class"
```
!!! note
While we support anonymous type serialization by converting to a `Dictionary<string, object>`, this is **not** a best practice and is **not recommended** when using native AOT.
We recommend using concrete classes and adding them to your `JsonSerializerContext`.
You can change where the Logger will output its logs by setting the LogOutput property.
We also provide a helper class for tests TestLoggerOutput or you can provider your own implementation of IConsoleWrapper.
--8<-- "docs/snippets/logging/Testing.cs:testing_setup"--8<-- "docs/snippets/logging/Testing.cs:test_example"If you are using ILogger interface you can inject the logger in a dedicated constructor for your Lambda function and thus you can mock your ILogger instance.
--8<-- "docs/snippets/logging/Testing.cs:ilogger_testing"