Skip to content

Commit d0c3a26

Browse files
authored
Merge branch 'develop' into chore/ua-change-env
2 parents 88fdaa3 + 26ecdc0 commit d0c3a26

File tree

11 files changed

+438
-172
lines changed

11 files changed

+438
-172
lines changed

.github/workflows/codeql-analysis.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ jobs:
3535

3636
# Initializes the CodeQL tools for scanning.
3737
- name: Initialize CodeQL
38-
uses: github/codeql-action/init@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2
38+
uses: github/codeql-action/init@4e828ff8d448a8a6e532957b1811f387a63867e8 # v3.29.4
3939
with:
4040
languages: ${{ matrix.language }}
4141

@@ -45,7 +45,7 @@ jobs:
4545
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
4646
# If this step fails, then you should remove it and run the build manually (see below)
4747
- name: Autobuild
48-
uses: github/codeql-action/autobuild@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2
48+
uses: github/codeql-action/autobuild@4e828ff8d448a8a6e532957b1811f387a63867e8 # v3.29.4
4949

5050
# ℹ️ Command-line programs to run using the OS shell.
5151
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
@@ -58,4 +58,4 @@ jobs:
5858
# ./location_of_script_within_repo/buildscript.sh
5959

6060
- name: Perform CodeQL Analysis
61-
uses: github/codeql-action/analyze@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2
61+
uses: github/codeql-action/analyze@4e828ff8d448a8a6e532957b1811f387a63867e8 # v3.29.4

.github/workflows/e2e-tests.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ jobs:
5151
node-version: "22"
5252

5353
- name: Setup dependencies
54-
uses: aws-powertools/actions/.github/actions/cached-node-modules@29979bc5339bf54f76a11ac36ff67701986bb0f0
54+
uses: aws-powertools/actions/.github/actions/cached-node-modules@7d2401cbbb232594bde7285bc5b8c0c78dcbe6e2
5555

5656
- name: Install AWS Lambda .NET CLI Tools
5757
run: dotnet tool install -g Amazon.Lambda.Tools
@@ -95,7 +95,7 @@ jobs:
9595
node-version: "22"
9696

9797
- name: Setup dependencies
98-
uses: aws-powertools/actions/.github/actions/cached-node-modules@29979bc5339bf54f76a11ac36ff67701986bb0f0
98+
uses: aws-powertools/actions/.github/actions/cached-node-modules@7d2401cbbb232594bde7285bc5b8c0c78dcbe6e2
9999

100100
- name: Install AWS Lambda .NET CLI Tools
101101
run: dotnet tool install -g Amazon.Lambda.Tools
@@ -163,7 +163,7 @@ jobs:
163163
node-version: "22"
164164

165165
- name: Setup dependencies
166-
uses: aws-powertools/actions/.github/actions/cached-node-modules@29979bc5339bf54f76a11ac36ff67701986bb0f0
166+
uses: aws-powertools/actions/.github/actions/cached-node-modules@7d2401cbbb232594bde7285bc5b8c0c78dcbe6e2
167167

168168
- name: Install AWS Lambda .NET CLI Tools
169169
run: dotnet tool install -g Amazon.Lambda.Tools
@@ -204,7 +204,7 @@ jobs:
204204
node-version: "22"
205205

206206
- name: Setup dependencies
207-
uses: aws-powertools/actions/.github/actions/cached-node-modules@29979bc5339bf54f76a11ac36ff67701986bb0f0
207+
uses: aws-powertools/actions/.github/actions/cached-node-modules@7d2401cbbb232594bde7285bc5b8c0c78dcbe6e2
208208

209209
- name: Install AWS Lambda .NET CLI Tools
210210
run: dotnet tool install -g Amazon.Lambda.Tools

.github/workflows/ossf_scorecard.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,6 @@ jobs:
4343

4444
# Upload the results to GitHub's code scanning dashboard.
4545
- name: "Upload to code-scanning"
46-
uses: github/codeql-action/upload-sarif@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2
46+
uses: github/codeql-action/upload-sarif@4e828ff8d448a8a6e532957b1811f387a63867e8 # v3.29.4
4747
with:
4848
sarif_file: results.sarif

docs/core/logging.md

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,7 @@ When debugging in non-production environments, you can instruct Logger to log th
446446
parameter or via `POWERTOOLS_LOGGER_LOG_EVENT` environment variable.
447447

448448
!!! warning
449-
Log event is disabled by default to prevent sensitive info being logged.
449+
Log event is disabled by default to prevent sensitive info being logged.
450450

451451
=== "Function.cs"
452452

@@ -471,8 +471,8 @@ You can set a Correlation ID using `CorrelationIdPath` parameter by passing
471471
a [JSON Pointer expression](https://datatracker.ietf.org/doc/html/draft-ietf-appsawg-json-pointer-03){target="_blank"}.
472472

473473
!!! Attention
474-
The JSON Pointer expression is `case sensitive`. In the bellow example `/headers/my_request_id_header` would work but
475-
`/Headers/my_request_id_header` would not find the element.
474+
The JSON Pointer expression is `case sensitive`. In the bellow example `/headers/my_request_id_header` would work but
475+
`/Headers/my_request_id_header` would not find the element.
476476

477477
=== "Function.cs"
478478

@@ -577,8 +577,8 @@ for known event sources, where either a request ID or X-Ray Trace ID are present
577577
## Appending additional keys
578578

579579
!!! info "Custom keys are persisted across warm invocations"
580-
Always set additional keys as part of your handler to ensure they have the latest value, or explicitly clear them with [
581-
`ClearState=true`](#clearing-all-state).
580+
Always set additional keys as part of your handler to ensure they have the latest value, or explicitly clear them with [
581+
`ClearState=true`](#clearing-all-state).
582582

583583
You can append your own keys to your existing logs via `AppendKey`. Typically this value would be passed into the
584584
function via the event. Appended keys are added to all subsequent log entries in the current execution from the point
@@ -683,7 +683,7 @@ It accepts any dictionary, and all keyword arguments will be added as part of th
683683
log statement.
684684

685685
!!! info
686-
Any keyword argument added using extra keys will not be persisted for subsequent messages.
686+
Any keyword argument added using extra keys will not be persisted for subsequent messages.
687687

688688
=== "Function.cs"
689689

@@ -782,8 +782,8 @@ You can dynamically set a percentage of your logs to **DEBUG** level via env var
782782
via `SamplingRate` parameter on attribute.
783783

784784
!!! info
785-
Configuration on environment variable is given precedence over sampling rate configuration on attribute, provided it's
786-
in valid value range.
785+
Configuration on environment variable is given precedence over sampling rate configuration on attribute, provided it's
786+
in valid value range.
787787

788788
=== "Sampling via attribute parameter"
789789

@@ -915,18 +915,18 @@ We support the following log levels:
915915
### Using AWS Lambda Advanced Logging Controls (ALC)
916916

917917
!!! question "When is it useful?"
918-
When you want to set a logging policy to drop informational or verbose logs for one or all AWS Lambda functions,
919-
regardless of runtime and logger used.
918+
When you want to set a logging policy to drop informational or verbose logs for one or all AWS Lambda functions,
919+
regardless of runtime and logger used.
920920

921921
With [AWS Lambda Advanced Logging Controls (ALC)](https://docs.aws.amazon.com/lambda/latest/dg/monitoring-cloudwatchlogs.html#monitoring-cloudwatchlogs-advanced)
922922
{target="_blank"}, you can enforce a minimum log level that Lambda will accept from your application code.
923923

924924
When enabled, you should keep `Logger` and ALC log level in sync to avoid data loss.
925925

926926
!!! warning "When using AWS Lambda Advanced Logging Controls (ALC)"
927-
- When Powertools Logger output is set to `PascalCase` **`Level`** property name will be replaced by **`LogLevel`** as
928-
a property name.
929-
- ALC takes precedence over **`POWERTOOLS_LOG_LEVEL`** and when setting it in code using **`[Logging(LogLevel = )]`**
927+
- When Powertools Logger output is set to `PascalCase` **`Level`** property name will be replaced by **`LogLevel`** as
928+
a property name.
929+
- ALC takes precedence over **`POWERTOOLS_LOG_LEVEL`** and when setting it in code using **`[Logging(LogLevel = )]`**
930930

931931
Here's a sequence diagram to demonstrate how ALC will drop both `Information` and `Debug` logs emitted from `Logger`,
932932
when ALC log level is stricter than `Logger`.
@@ -985,8 +985,8 @@ customize the serialization of Powertools Logger.
985985
This is useful when you want to change the casing of the property names or use a different naming convention.
986986

987987
!!! info
988-
If you want to preserve the original casing of the property names (keys), you can set the `DictionaryKeyPolicy` to
989-
`null`.
988+
If you want to preserve the original casing of the property names (keys), you can set the `DictionaryKeyPolicy` to
989+
`null`.
990990

991991
```csharp
992992
builder.Logging.AddPowertoolsLogger(options =>
@@ -999,6 +999,19 @@ builder.Logging.AddPowertoolsLogger(options =>
999999
});
10001000
```
10011001

1002+
!!! warning
1003+
When using `builder.Logging.AddPowertoolsLogger` method it will use any already configured logging providers (file loggers, database loggers, third-party providers).
1004+
1005+
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
1006+
1007+
```csharp
1008+
builder.Logging.AddPowertoolsLogger(config =>
1009+
{
1010+
config.Service = "TestService";
1011+
config.LoggerOutputCase = LoggerOutputCase.PascalCase;
1012+
}, clearExistingProviders: true);
1013+
```
1014+
10021015
### Custom Log formatter (Bring Your Own Formatter)
10031016

10041017
You can customize the structure (keys and values) of your log entries by implementing a custom log formatter and

libraries/src/AWS.Lambda.Powertools.Common/Core/ConsoleWrapper.cs

Lines changed: 64 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ public class ConsoleWrapper : IConsoleWrapper
88
{
99
private static bool _override;
1010
private static TextWriter _testOutputStream;
11-
private static bool _outputResetPerformed = false;
1211
private static bool _inTestMode = false;
1312

1413
/// <inheritdoc />
@@ -20,7 +19,7 @@ public void WriteLine(string message)
2019
}
2120
else
2221
{
23-
EnsureConsoleOutputOnce();
22+
EnsureConsoleOutput();
2423
Console.WriteLine(message);
2524
}
2625
}
@@ -34,7 +33,7 @@ public void Debug(string message)
3433
}
3534
else
3635
{
37-
EnsureConsoleOutputOnce();
36+
EnsureConsoleOutput();
3837
System.Diagnostics.Debug.WriteLine(message);
3938
}
4039
}
@@ -50,9 +49,9 @@ public void Error(string message)
5049
{
5150
if (!_override)
5251
{
53-
var errordOutput = new StreamWriter(Console.OpenStandardError());
54-
errordOutput.AutoFlush = true;
55-
Console.SetError(errordOutput);
52+
var errorOutput = new StreamWriter(Console.OpenStandardError());
53+
errorOutput.AutoFlush = true;
54+
Console.SetError(errorOutput);
5655
}
5756
Console.Error.WriteLine(message);
5857
}
@@ -70,23 +69,69 @@ public static void SetOut(TextWriter consoleOut)
7069
Console.SetOut(consoleOut);
7170
}
7271

73-
private static void EnsureConsoleOutputOnce()
72+
private static void EnsureConsoleOutput()
7473
{
75-
if (_outputResetPerformed) return;
76-
OverrideLambdaLogger();
77-
_outputResetPerformed = true;
74+
// Check if we need to override console output for Lambda environment
75+
if (ShouldOverrideConsole())
76+
{
77+
OverrideLambdaLogger();
78+
}
79+
}
80+
81+
private static bool ShouldOverrideConsole()
82+
{
83+
// Don't override if we're in test mode
84+
if (_inTestMode) return false;
85+
86+
// Always override in Lambda environment to prevent Lambda's log wrapping
87+
var isLambda = !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("AWS_LAMBDA_FUNCTION_NAME"));
88+
89+
return isLambda && (!_override || HasLambdaReInterceptedConsole());
90+
}
91+
92+
internal static bool HasLambdaReInterceptedConsole()
93+
{
94+
return HasLambdaReInterceptedConsole(() => Console.Out);
7895
}
7996

80-
private static void OverrideLambdaLogger()
97+
internal static bool HasLambdaReInterceptedConsole(Func<TextWriter> consoleOutAccessor)
8198
{
82-
if (_override)
99+
// Lambda might re-intercept console between init and handler execution
100+
try
101+
{
102+
var currentOut = consoleOutAccessor();
103+
// Check if current output stream looks like it might be Lambda's wrapper
104+
var typeName = currentOut.GetType().FullName ?? "";
105+
return typeName.Contains("Lambda") || typeName == "System.IO.TextWriter+SyncTextWriter";
106+
}
107+
catch
108+
{
109+
return true; // Assume re-interception if we can't determine
110+
}
111+
}
112+
113+
internal static void OverrideLambdaLogger()
114+
{
115+
OverrideLambdaLogger(() => Console.OpenStandardOutput());
116+
}
117+
118+
internal static void OverrideLambdaLogger(Func<Stream> standardOutputOpener)
119+
{
120+
try
121+
{
122+
// Force override of LambdaLogger
123+
var standardOutput = new StreamWriter(standardOutputOpener())
124+
{
125+
AutoFlush = true
126+
};
127+
Console.SetOut(standardOutput);
128+
_override = true;
129+
}
130+
catch (Exception)
83131
{
84-
return;
132+
// Log the failure but don't throw - degraded functionality is better than crash
133+
_override = false;
85134
}
86-
// Force override of LambdaLogger
87-
var standardOutput = new StreamWriter(Console.OpenStandardOutput());
88-
standardOutput.AutoFlush = true;
89-
Console.SetOut(standardOutput);
90135
}
91136

92137
internal static void WriteLine(string logLevel, string message)
@@ -102,14 +147,14 @@ public static void ResetForTest()
102147
_override = false;
103148
_inTestMode = false;
104149
_testOutputStream = null;
105-
_outputResetPerformed = false;
106150
}
107151

108152
/// <summary>
109153
/// Clear the output reset flag
110154
/// </summary>
111155
public static void ClearOutputResetFlag()
112156
{
113-
_outputResetPerformed = false;
157+
// This method is kept for backward compatibility but no longer needed
158+
// since we removed the _outputResetPerformed flag
114159
}
115160
}

libraries/src/AWS.Lambda.Powertools.Logging/PowertoolsLoggingBuilderExtensions.cs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ internal static PowertoolsLoggerConfiguration GetCurrentConfiguration()
5656
/// Adds the Powertools logger to the logging builder with default configuration.
5757
/// </summary>
5858
/// <param name="builder">The logging builder to configure.</param>
59+
/// <param name="clearExistingProviders">Opt-in to clear providers for Powertools-only output</param>
5960
/// <returns>The logging builder for further configuration.</returns>
6061
/// <remarks>
6162
/// This method registers the Powertools logger with default settings. The logger will output
@@ -78,14 +79,24 @@ internal static PowertoolsLoggerConfiguration GetCurrentConfiguration()
7879
/// </code>
7980
/// </example>
8081
public static ILoggingBuilder AddPowertoolsLogger(
81-
this ILoggingBuilder builder)
82+
this ILoggingBuilder builder,
83+
bool clearExistingProviders = false)
8284
{
85+
if (clearExistingProviders)
86+
{
87+
builder.ClearProviders();
88+
}
89+
8390
builder.AddConfiguration();
84-
91+
8592
builder.Services.TryAddSingleton<IPowertoolsEnvironment, PowertoolsEnvironment>();
8693
builder.Services.TryAddSingleton<IPowertoolsConfigurations>(sp =>
8794
new PowertoolsConfigurations(sp.GetRequiredService<IPowertoolsEnvironment>()));
8895

96+
// automatically register ILogger
97+
builder.Services.TryAddSingleton<ILogger>(provider =>
98+
provider.GetRequiredService<ILoggerFactory>().CreatePowertoolsLogger());
99+
89100
builder.Services.TryAddEnumerable(
90101
ServiceDescriptor.Singleton<ILoggerProvider, PowertoolsLoggerProvider>(provider =>
91102
{
@@ -111,6 +122,7 @@ public static ILoggingBuilder AddPowertoolsLogger(
111122
/// </summary>
112123
/// <param name="builder">The logging builder to configure.</param>
113124
/// <param name="configure"></param>
125+
/// <param name="clearExistingProviders">Opt-in to clear providers for Powertools-only output</param>
114126
/// <returns>The logging builder for further configuration.</returns>
115127
/// <remarks>
116128
/// This method registers the Powertools logger with default settings. The logger will output
@@ -155,10 +167,11 @@ public static ILoggingBuilder AddPowertoolsLogger(
155167
/// </example>
156168
public static ILoggingBuilder AddPowertoolsLogger(
157169
this ILoggingBuilder builder,
158-
Action<PowertoolsLoggerConfiguration> configure)
170+
Action<PowertoolsLoggerConfiguration> configure,
171+
bool clearExistingProviders = false)
159172
{
160173
// Add configuration
161-
builder.AddPowertoolsLogger();
174+
builder.AddPowertoolsLogger(clearExistingProviders);
162175

163176
// Create initial configuration
164177
var options = new PowertoolsLoggerConfiguration();

libraries/src/AWS.Lambda.Powertools.Metrics/Metrics.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,10 @@ void IMetrics.AddMetric(string key, double value, MetricUnit unit, MetricResolut
182182
throw new ArgumentNullException(
183183
nameof(key),
184184
"'AddMetric' method requires a valid metrics key. 'Null' or empty values are not allowed.");
185+
if (key.Length > 255)
186+
throw new ArgumentOutOfRangeException(
187+
nameof(key),
188+
"'AddMetric' method requires a valid metrics key. Key exceeds the allowed length constraint.");
185189

186190
if (value < 0)
187191
{

0 commit comments

Comments
 (0)