Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix issue with not correctly detecting "warning" log level. #1800

Merged
merged 2 commits into from
Sep 4, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,10 @@ public WrapperTextWriter(TextWriter innerWriter, string defaultLogLevel)
{
_minmumLogLevel = LogLevel.Critical;
}
else if (string.Equals(envLogLevel, "warn", StringComparison.InvariantCultureIgnoreCase))
{
_minmumLogLevel = LogLevel.Warning;
}
else if (Enum.TryParse<LogLevel>(envLogLevel, true, out var result))
{
_minmumLogLevel = result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="AWSSDK.IdentityManagement" Version="3.7.100.98" />
<PackageReference Include="AWSSDK.Lambda" Version="3.7.105.17" />
<PackageReference Include="AWSSDK.IdentityManagement" Version="3.7.402.7" />
<PackageReference Include="AWSSDK.Lambda" Version="3.7.402.3" />
<PackageReference Include="AWSSDK.S3" Version="3.7.103.34" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
Expand All @@ -32,7 +32,7 @@
<PackageReference Include="xunit" Version="2.4.2" />

<!-- This needs to be referenced to allow testing via AssumeRole credentials -->
<PackageReference Include="AWSSDK.SecurityToken" Version="3.7.101.32" />
<PackageReference Include="AWSSDK.SecurityToken" Version="3.7.400.13" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,9 +198,11 @@ protected async Task<InvokeResponse> InvokeFunctionAsync(IAmazonLambda lambdaCli
return await lambdaClient.InvokeAsync(request);
}

protected async Task UpdateHandlerAsync(IAmazonLambda lambdaClient, string handler, Dictionary<string, string> environmentVariables = null)
protected async Task UpdateHandlerAsync(IAmazonLambda lambdaClient, string handler, Dictionary<string, string> environmentVariables = null, RuntimeLogLevel? logLevel = null)
{
if(environmentVariables == null)
await WaitForFunctionToBeReady(lambdaClient);

if (environmentVariables == null)
{
environmentVariables = new Dictionary<string, string>();
}
Expand All @@ -216,8 +218,30 @@ protected async Task UpdateHandlerAsync(IAmazonLambda lambdaClient, string handl
Variables = environmentVariables
}
};

if (logLevel == null)
{
updateFunctionConfigurationRequest.LoggingConfig = new LoggingConfig
{
LogFormat = LogFormat.Text
};
}
else
{
updateFunctionConfigurationRequest.LoggingConfig = new LoggingConfig
{
ApplicationLogLevel = ConvertRuntimeLogLevel(logLevel.Value),
LogFormat = LogFormat.JSON
};
}

await lambdaClient.UpdateFunctionConfigurationAsync(updateFunctionConfigurationRequest);

await WaitForFunctionToBeReady(lambdaClient);
}

private async Task WaitForFunctionToBeReady(IAmazonLambda lambdaClient)
{
// Wait for eventual consistency of function change.
var getConfigurationRequest = new GetFunctionConfigurationRequest { FunctionName = FunctionName };
GetFunctionConfigurationResponse getConfigurationResponse = null;
Expand Down Expand Up @@ -344,5 +368,58 @@ protected class NoDeploymentPackageFoundException : Exception
{

}

private ApplicationLogLevel ConvertRuntimeLogLevel(RuntimeLogLevel runtimeLogLevel)
{
switch (runtimeLogLevel)
{
case RuntimeLogLevel.Trace:
return ApplicationLogLevel.TRACE;
case RuntimeLogLevel.Debug:
return ApplicationLogLevel.DEBUG;
case RuntimeLogLevel.Information:
return ApplicationLogLevel.INFO;
case RuntimeLogLevel.Warning:
return ApplicationLogLevel.WARN;
case RuntimeLogLevel.Error:
return ApplicationLogLevel.ERROR;
case RuntimeLogLevel.Critical:
return ApplicationLogLevel.FATAL;
default:
throw new ArgumentException("Unknown log level: " + runtimeLogLevel);
}
}

public enum RuntimeLogLevel
{
/// <summary>
/// Trace level logging
/// </summary>
Trace = 0,
/// <summary>
/// Debug level logging
/// </summary>
Debug = 1,

/// <summary>
/// Information level logging
/// </summary>
Information = 2,

/// <summary>
/// Warning level logging
/// </summary>
Warning = 3,

/// <summary>
/// Error level logging
/// </summary>
Error = 4,

/// <summary>
/// Critical level logging
/// </summary>
Critical = 5
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,21 @@ protected virtual async Task TestAllHandlersAsync()
await RunTestExceptionAsync(lambdaClient, "ExceptionNonAsciiCharacterUnwrappedAsync", "", "Exception", "Unhandled exception with non ASCII character: ♂");
await RunTestSuccessAsync(lambdaClient, "UnintendedDisposeTest", "not-used", "UnintendedDisposeTest-SUCCESS");
await RunTestSuccessAsync(lambdaClient, "LoggingStressTest", "not-used", "LoggingStressTest-success");
await RunLoggingTestAsync(lambdaClient, "LoggingTest", null);
await RunLoggingTestAsync(lambdaClient, "LoggingTest", "debug");

await RunLoggingTestAsync(lambdaClient, "LoggingTest", RuntimeLogLevel.Trace, LogConfigSource.LambdaAPI);
await RunLoggingTestAsync(lambdaClient, "LoggingTest", RuntimeLogLevel.Debug, LogConfigSource.LambdaAPI);
await RunLoggingTestAsync(lambdaClient, "LoggingTest", RuntimeLogLevel.Information, LogConfigSource.LambdaAPI);
await RunLoggingTestAsync(lambdaClient, "LoggingTest", RuntimeLogLevel.Warning, LogConfigSource.LambdaAPI);
await RunLoggingTestAsync(lambdaClient, "LoggingTest", RuntimeLogLevel.Error, LogConfigSource.LambdaAPI);
await RunLoggingTestAsync(lambdaClient, "LoggingTest", RuntimeLogLevel.Critical, LogConfigSource.LambdaAPI);
await RunLoggingTestAsync(lambdaClient, "LoggingTest", RuntimeLogLevel.Trace, LogConfigSource.DotnetEnvironment);
await RunLoggingTestAsync(lambdaClient, "LoggingTest", RuntimeLogLevel.Debug, LogConfigSource.DotnetEnvironment);
await RunLoggingTestAsync(lambdaClient, "LoggingTest", RuntimeLogLevel.Information, LogConfigSource.DotnetEnvironment);
await RunLoggingTestAsync(lambdaClient, "LoggingTest", RuntimeLogLevel.Warning, LogConfigSource.DotnetEnvironment);
await RunLoggingTestAsync(lambdaClient, "LoggingTest", RuntimeLogLevel.Error, LogConfigSource.DotnetEnvironment);
await RunLoggingTestAsync(lambdaClient, "LoggingTest", RuntimeLogLevel.Critical, LogConfigSource.DotnetEnvironment);


await RunUnformattedLoggingTestAsync(lambdaClient, "LoggingTest");

await RunTestSuccessAsync(lambdaClient, "ToUpperAsync", "message", "ToUpperAsync-MESSAGE");
Expand Down Expand Up @@ -207,37 +220,83 @@ private async Task RunTestExceptionAsync(AmazonLambdaClient lambdaClient, string
}
}

private async Task RunLoggingTestAsync(AmazonLambdaClient lambdaClient, string handler, string logLevel)
// The .NET Lambda runtime has a legacy environment variable for configuring the log level. This enum is used in the test to choose
// whether the legacy environment variable should be set or use the new properties in the update configuration api for setting log level.
enum LogConfigSource { LambdaAPI, DotnetEnvironment}
private async Task RunLoggingTestAsync(AmazonLambdaClient lambdaClient, string handler, RuntimeLogLevel? runtimeLogLevel, LogConfigSource configSource)
{
var environmentVariables = new Dictionary<string, string>();
if(!string.IsNullOrEmpty(logLevel))
if(runtimeLogLevel.HasValue && configSource == LogConfigSource.DotnetEnvironment)
{
environmentVariables["AWS_LAMBDA_HANDLER_LOG_LEVEL"] = logLevel;
environmentVariables["AWS_LAMBDA_HANDLER_LOG_LEVEL"] = runtimeLogLevel.Value.ToString().ToLowerInvariant();
}
await UpdateHandlerAsync(lambdaClient, handler, environmentVariables);
await UpdateHandlerAsync(lambdaClient, handler, environmentVariables, configSource == LogConfigSource.LambdaAPI ? runtimeLogLevel : null);

var invokeResponse = await InvokeFunctionAsync(lambdaClient, JsonConvert.SerializeObject(""));
Assert.True(invokeResponse.HttpStatusCode == System.Net.HttpStatusCode.OK);
Assert.True(invokeResponse.FunctionError == null);

var log = System.Text.UTF8Encoding.UTF8.GetString(Convert.FromBase64String(invokeResponse.LogResult));

Assert.Contains("info\tA information log", log);
Assert.Contains("warn\tA warning log", log);
Assert.Contains("fail\tA error log", log);
Assert.Contains("crit\tA critical log", log);
if (!runtimeLogLevel.HasValue)
runtimeLogLevel = RuntimeLogLevel.Information;

if (runtimeLogLevel <= RuntimeLogLevel.Trace)
{
Assert.Contains("A trace log", log);
}
else
{
Assert.DoesNotContain("A trace log", log);
}

if (runtimeLogLevel <= RuntimeLogLevel.Debug)
{
Assert.Contains("A debug log", log);
}
else
{
Assert.DoesNotContain("A debug log", log);
}

if (runtimeLogLevel <= RuntimeLogLevel.Information)
{
Assert.Contains("A information log", log);
Assert.Contains("A stdout info message", log);
}
else
{
Assert.DoesNotContain("A information log", log);
Assert.DoesNotContain("A stdout info message", log);
}

Assert.Contains("info\tA stdout info message", log);
if (runtimeLogLevel <= RuntimeLogLevel.Warning)
{
Assert.Contains("A warning log", log);
}
else
{
Assert.DoesNotContain("A warning log", log);
}

Assert.Contains("fail\tA stderror error message", log);
if (runtimeLogLevel <= RuntimeLogLevel.Error)
{
Assert.Contains("A error log", log);
Assert.Contains("A stderror error message", log);
}
else
{
Assert.DoesNotContain("A error log", log);
Assert.DoesNotContain("A stderror error message", log);
}

if (string.IsNullOrEmpty(logLevel))
if (runtimeLogLevel <= RuntimeLogLevel.Critical)
{
Assert.DoesNotContain($"a {logLevel} log".ToLower(), log.ToLower());
Assert.Contains("A critical log", log);
}
else
{
Assert.Contains($"a {logLevel} log".ToLower(), log.ToLower());
Assert.DoesNotContain("A critical log", log);
}
}

Expand Down
Loading