Skip to content

Commit

Permalink
Add structured logging support to Amazon.Lambda.RuntimeSupport (#1803)
Browse files Browse the repository at this point in the history
  • Loading branch information
normj authored Sep 4, 2024
1 parent 5d4e18b commit d4eef2a
Show file tree
Hide file tree
Showing 28 changed files with 2,373 additions and 95 deletions.
2 changes: 1 addition & 1 deletion Libraries/src/Amazon.Lambda.Core/Amazon.Lambda.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<TargetFrameworks>netstandard2.0;net6.0;net8.0</TargetFrameworks>
<Description>Amazon Lambda .NET Core support - Core package.</Description>
<AssemblyTitle>Amazon.Lambda.Core</AssemblyTitle>
<VersionPrefix>2.2.0</VersionPrefix>
<VersionPrefix>2.3.0</VersionPrefix>
<AssemblyName>Amazon.Lambda.Core</AssemblyName>
<PackageId>Amazon.Lambda.Core</PackageId>
<PackageTags>AWS;Amazon;Lambda</PackageTags>
Expand Down
223 changes: 221 additions & 2 deletions Libraries/src/Amazon.Lambda.Core/ILambdaLogger.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
using System;
using System.Runtime.Versioning;

namespace Amazon.Lambda.Core
{
#if NET6_0_OR_GREATER
Expand Down Expand Up @@ -62,7 +65,7 @@ public interface ILambdaLogger
#if NET6_0_OR_GREATER

/// <summary>
/// Log message catagorized by the given log level
/// Log message categorized by the given log level
/// <para>
/// To configure the minimum log level set the AWS_LAMBDA_HANDLER_LOG_LEVEL environment variable. The value should be set
/// to one of the values in the LogLevel enumeration. The default minimum log level is "Information".
Expand All @@ -73,7 +76,7 @@ public interface ILambdaLogger
void Log(string level, string message) => LogLine(message);

/// <summary>
/// Log message catagorized by the given log level
/// Log message categorized by the given log level
/// <para>
/// To configure the minimum log level set the AWS_LAMBDA_HANDLER_LOG_LEVEL environment variable. The value should be set
/// to one of the values in the LogLevel enumeration. The default minimum log level is "Information".
Expand Down Expand Up @@ -142,6 +145,222 @@ public interface ILambdaLogger
/// </summary>
/// <param name="message"></param>
void LogCritical(string message) => Log(LogLevel.Critical.ToString(), message);


private const string ParameterizedPreviewMessage =
"Parameterized logging is in preview till a new version of .NET Lambda runtime client that supports parameterized logging " +
"has been deployed to the .NET Lambda managed runtime. Till deployment has been made the feature can be used by deploying as an " +
"executable including the latest version of Amazon.Lambda.RuntimeSupport and setting the \"EnablePreviewFeatures\" in the Lambda " +
"project file to \"true\"";

/// <summary>
/// Log message categorized by the given log level
/// <para>
/// To configure the minimum log level set the AWS_LAMBDA_HANDLER_LOG_LEVEL environment variable. The value should be set
/// to one of the values in the LogLevel enumeration. The default minimum log level is "Information".
/// </para>
/// </summary>
/// <param name="level">Log level of the message.</param>
/// <param name="message">Message to log.</param>
/// <param name="args">Values to be replaced in log messages that are parameterized.</param>
[RequiresPreviewFeatures(ParameterizedPreviewMessage)]
void Log(string level, string message, params object[] args) => Log(level, message, args);

/// <summary>
/// Log message categorized by the given log level
/// <para>
/// To configure the minimum log level set the AWS_LAMBDA_HANDLER_LOG_LEVEL environment variable. The value should be set
/// to one of the values in the LogLevel enumeration. The default minimum log level is "Information".
/// </para>
/// </summary>
/// <param name="level">Log level of the message.</param>
/// <param name="exception">Exception to include with the logging.</param>
/// <param name="message">Message to log.</param>
/// <param name="args">Values to be replaced in log messages that are parameterized.</param>
[RequiresPreviewFeatures(ParameterizedPreviewMessage)]
void Log(string level, Exception exception, string message, params object[] args)
{
Log(level, message, args);
Log(level, exception.ToString(), args);
}

/// <summary>
/// Log message categorized by the given log level
/// <para>
/// To configure the minimum log level set the AWS_LAMBDA_HANDLER_LOG_LEVEL environment variable. The value should be set
/// to one of the values in the LogLevel enumeration. The default minimum log level is "Information".
/// </para>
/// </summary>
/// <param name="level">Log level of the message.</param>
/// <param name="message">Message to log.</param>
/// <param name="args">Values to be replaced in log messages that are parameterized.</param>
[RequiresPreviewFeatures(ParameterizedPreviewMessage)]
void Log(LogLevel level, string message, params object[] args) => Log(level.ToString(), message, args);

/// <summary>
/// Log message categorized by the given log level
/// <para>
/// To configure the minimum log level set the AWS_LAMBDA_HANDLER_LOG_LEVEL environment variable. The value should be set
/// to one of the values in the LogLevel enumeration. The default minimum log level is "Information".
/// </para>
/// </summary>
/// <param name="level">Log level of the message.</param>
/// <param name="exception">Exception to include with the logging.</param>
/// <param name="message">Message to log.</param>
/// <param name="args">Values to be replaced in log messages that are parameterized.</param>
[RequiresPreviewFeatures(ParameterizedPreviewMessage)]
void Log(LogLevel level, Exception exception, string message, params object[] args) => Log(level.ToString(), exception, message, args);

/// <summary>
/// Log trace message.
/// <para>
/// To configure the minimum log level set the AWS_LAMBDA_HANDLER_LOG_LEVEL environment variable. The value should be set
/// to one of the values in the LogLevel enumeration. The default minimum log level is "Information".
/// </para>
/// </summary>
/// <param name="message">Message to log.</param>
/// <param name="args">Values to be replaced in log messages that are parameterized.</param>
[RequiresPreviewFeatures(ParameterizedPreviewMessage)]
void LogTrace(string message, params object[] args) => Log(LogLevel.Trace.ToString(), message, args);

/// <summary>
/// Log trace message.
/// <para>
/// To configure the minimum log level set the AWS_LAMBDA_HANDLER_LOG_LEVEL environment variable. The value should be set
/// to one of the values in the LogLevel enumeration. The default minimum log level is "Information".
/// </para>
/// </summary>
/// <param name="exception">Exception to include with the logging.</param>
/// <param name="message">Message to log.</param>
/// <param name="args">Values to be replaced in log messages that are parameterized.</param>
[RequiresPreviewFeatures(ParameterizedPreviewMessage)]
void LogTrace(Exception exception, string message, params object[] args) => Log(LogLevel.Trace.ToString(), exception, message, args);

/// <summary>
/// Log debug message.
/// <para>
/// To configure the minimum log level set the AWS_LAMBDA_HANDLER_LOG_LEVEL environment variable. The value should be set
/// to one of the values in the LogLevel enumeration. The default minimum log level is "Information".
/// </para>
/// </summary>
/// <param name="message">Message to log.</param>
/// <param name="args">Values to be replaced in log messages that are parameterized.</param>
[RequiresPreviewFeatures(ParameterizedPreviewMessage)]
void LogDebug(string message, params object[] args) => Log(LogLevel.Debug.ToString(), message, args);

/// <summary>
/// Log debug message.
/// <para>
/// To configure the minimum log level set the AWS_LAMBDA_HANDLER_LOG_LEVEL environment variable. The value should be set
/// to one of the values in the LogLevel enumeration. The default minimum log level is "Information".
/// </para>
/// </summary>
/// <param name="exception">Exception to include with the logging.</param>
/// <param name="message">Message to log.</param>
/// <param name="args">Values to be replaced in log messages that are parameterized.</param>
[RequiresPreviewFeatures(ParameterizedPreviewMessage)]
void LogDebug(Exception exception, string message, params object[] args) => Log(LogLevel.Debug.ToString(), exception, message, args);

/// <summary>
/// Log information message.
/// <para>
/// To configure the minimum log level set the AWS_LAMBDA_HANDLER_LOG_LEVEL environment variable. The value should be set
/// to one of the values in the LogLevel enumeration. The default minimum log level is "Information".
/// </para>
/// </summary>
/// <param name="message">Message to log.</param>
/// <param name="args">Values to be replaced in log messages that are parameterized.</param>
[RequiresPreviewFeatures(ParameterizedPreviewMessage)]
void LogInformation(string message, params object[] args) => Log(LogLevel.Information.ToString(), message, args);

/// <summary>
/// Log information message.
/// <para>
/// To configure the minimum log level set the AWS_LAMBDA_HANDLER_LOG_LEVEL environment variable. The value should be set
/// to one of the values in the LogLevel enumeration. The default minimum log level is "Information".
/// </para>
/// </summary>
/// <param name="exception">Exception to include with the logging.</param>
/// <param name="message">Message to log.</param>
/// <param name="args">Values to be replaced in log messages that are parameterized.</param>
[RequiresPreviewFeatures(ParameterizedPreviewMessage)]
void LogInformation(Exception exception, string message, params object[] args) => Log(LogLevel.Information.ToString(), exception, message, args);

/// <summary>
/// Log warning message.
/// <para>
/// To configure the minimum log level set the AWS_LAMBDA_HANDLER_LOG_LEVEL environment variable. The value should be set
/// to one of the values in the LogLevel enumeration. The default minimum log level is "Information".
/// </para>
/// </summary>
/// <param name="message">Message to log.</param>
/// <param name="args">Values to be replaced in log messages that are parameterized.</param>
[RequiresPreviewFeatures(ParameterizedPreviewMessage)]
void LogWarning(string message, params object[] args) => Log(LogLevel.Warning.ToString(), message, args);

/// <summary>
/// Log warning message.
/// <para>
/// To configure the minimum log level set the AWS_LAMBDA_HANDLER_LOG_LEVEL environment variable. The value should be set
/// to one of the values in the LogLevel enumeration. The default minimum log level is "Information".
/// </para>
/// </summary>
/// <param name="exception">Exception to include with the logging.</param>
/// <param name="message">Message to log.</param>
/// <param name="args">Values to be replaced in log messages that are parameterized.</param>
[RequiresPreviewFeatures(ParameterizedPreviewMessage)]
void LogWarning(Exception exception, string message, params object[] args) => Log(LogLevel.Warning.ToString(), exception, message, args);

/// <summary>
/// Log error message.
/// <para>
/// To configure the minimum log level set the AWS_LAMBDA_HANDLER_LOG_LEVEL environment variable. The value should be set
/// to one of the values in the LogLevel enumeration. The default minimum log level is "Information".
/// </para>
/// </summary>
/// <param name="message">Message to log.</param>
/// <param name="args">Values to be replaced in log messages that are parameterized.</param>
[RequiresPreviewFeatures(ParameterizedPreviewMessage)]
void LogError(string message, params object[] args) => Log(LogLevel.Error.ToString(), message, args);

/// <summary>
/// Log error message.
/// <para>
/// To configure the minimum log level set the AWS_LAMBDA_HANDLER_LOG_LEVEL environment variable. The value should be set
/// to one of the values in the LogLevel enumeration. The default minimum log level is "Information".
/// </para>
/// </summary>
/// <param name="exception">Exception to include with the logging.</param>
/// <param name="message">Message to log.</param>
/// <param name="args">Values to be replaced in log messages that are parameterized.</param>
[RequiresPreviewFeatures(ParameterizedPreviewMessage)]
void LogError(Exception exception, string message, params object[] args) => Log(LogLevel.Error.ToString(), exception, message, args);

/// <summary>
/// Log critical message.
/// <para>
/// To configure the minimum log level set the AWS_LAMBDA_HANDLER_LOG_LEVEL environment variable. The value should be set
/// to one of the values in the LogLevel enumeration. The default minimum log level is "Information".
/// </para>
/// </summary>
/// <param name="message">Message to log.</param>
/// <param name="args">Values to be replaced in log messages that are parameterized.</param>
[RequiresPreviewFeatures(ParameterizedPreviewMessage)]
void LogCritical(string message, params object[] args) => Log(LogLevel.Critical.ToString(), message, args);

/// <summary>
/// Log critical message.
/// <para>
/// To configure the minimum log level set the AWS_LAMBDA_HANDLER_LOG_LEVEL environment variable. The value should be set
/// to one of the values in the LogLevel enumeration. The default minimum log level is "Information".
/// </para>
/// </summary>
/// <param name="exception">Exception to include with the logging.</param>
/// <param name="message">Message to log.</param>
/// <param name="args">Values to be replaced in log messages that are parameterized.</param>
[RequiresPreviewFeatures(ParameterizedPreviewMessage)]
void LogCritical(Exception exception, string message, params object[] args) => Log(LogLevel.Critical.ToString(), exception, message, args);

#endif

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

<PropertyGroup>
<TargetFrameworks>netstandard2.0;net5.0;net6.0;net8.0</TargetFrameworks>
<VersionPrefix>1.10.0</VersionPrefix>
<VersionPrefix>1.11.0</VersionPrefix>
<Description>Provides a bootstrap and Lambda Runtime API Client to help you to develop custom .NET Core Lambda Runtimes.</Description>
<AssemblyTitle>Amazon.Lambda.RuntimeSupport</AssemblyTitle>
<AssemblyName>Amazon.Lambda.RuntimeSupport</AssemblyName>
Expand All @@ -13,6 +13,7 @@
<PackageReadmeFile>README.md</PackageReadmeFile>
<GenerateAssemblyVersionAttribute>true</GenerateAssemblyVersionAttribute>
<GenerateAssemblyFileVersionAttribute>true</GenerateAssemblyFileVersionAttribute>
<LangVersion>9.0</LangVersion>
</PropertyGroup>

<PropertyGroup Condition=" '$(ExecutableOutputType)'=='true' ">
Expand All @@ -23,7 +24,6 @@
<WarningsAsErrors>IL2026,IL2067,IL2075</WarningsAsErrors>
<IsTrimmable>true</IsTrimmable>
<EnableTrimAnalyzer>true</EnableTrimAnalyzer>
<EnableTrimAnalyzer>true</EnableTrimAnalyzer>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ internal class Constants
internal const string AWS_LAMBDA_INITIALIZATION_TYPE_PC = "provisioned-concurrency";
internal const string AWS_LAMBDA_INITIALIZATION_TYPE_ON_DEMAND = "on-demand";

internal const string NET_RIC_LOG_LEVEL_ENVIRONMENT_VARIABLE = "AWS_LAMBDA_HANDLER_LOG_LEVEL";
internal const string NET_RIC_LOG_FORMAT_ENVIRONMENT_VARIABLE = "AWS_LAMBDA_HANDLER_LOG_FORMAT";

internal const string LAMBDA_LOG_LEVEL_ENVIRONMENT_VARIABLE = "AWS_LAMBDA_LOG_LEVEL";
internal const string LAMBDA_LOG_FORMAT_ENVIRONMENT_VARIABLE = "AWS_LAMBDA_LOG_FORMAT";

internal const string LAMBDA_LOG_FORMAT_JSON = "Json";

internal enum AwsLambdaDotNetPreJit
{
Never,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Amazon.Lambda.Core;
using Amazon.Lambda.RuntimeSupport.Bootstrap;
using Amazon.Lambda.RuntimeSupport.Helpers;

Expand Down Expand Up @@ -252,9 +253,11 @@ public static HttpClient ConstructHttpClient()

private void WriteUnhandledExceptionToLog(Exception exception)
{
// Console.Error.WriteLine are redirected to the IConsoleLoggerWriter which
// will take care of writing to the function's log stream.
#if NET6_0_OR_GREATER
Client.ConsoleLogger.FormattedWriteLine(LogLevel.Error.ToString(), exception, null);
#else
Console.Error.WriteLine(exception);
#endif
}

#if NET8_0_OR_GREATER
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
* permissions and limitations under the License.
*/

using Amazon.Lambda.RuntimeSupport.Helpers;
using System;
using System.IO;
using System.Threading;
Expand All @@ -25,6 +26,11 @@ namespace Amazon.Lambda.RuntimeSupport
/// </summary>
public interface IRuntimeApiClient
{
/// <summary>
/// Logger used for formatting log messages into the user's CloudWatch Log stream.
/// </summary>
IConsoleLoggerWriter ConsoleLogger { get; }

/// <summary>
/// Report an initialization error as an asynchronous operation.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ public class RuntimeApiClient : IRuntimeApiClient
internal Func<Exception, ExceptionInfo> ExceptionConverter { get; set; }
internal LambdaEnvironment LambdaEnvironment { get; set; }

/// <inheritdoc/>
public IConsoleLoggerWriter ConsoleLogger => _consoleLoggerRedirector;

/// <summary>
/// Create a new RuntimeApiClient
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
using Amazon.Lambda.Core;
using Amazon.Lambda.RuntimeSupport.Helpers;
using System;
using System.Runtime.Versioning;

namespace Amazon.Lambda.RuntimeSupport
{
Expand Down Expand Up @@ -44,6 +45,24 @@ public void Log(string level, string message)
{
_consoleLoggerRedirector.FormattedWriteLine(level, message);
}

private const string ParameterizedPreviewMessage =
"Parameterized logging is in preview till a new version of .NET Lambda runtime client that supports parameterized logging " +
"has been deployed to the .NET Lambda managed runtime. Till deployment has been made the feature can be used by deploying as an " +
"executable including the latest version of Amazon.Lambda.RuntimeSupport and setting the \"LangVersion\" in the Lambda " +
"project file to \"preview\"";

[RequiresPreviewFeatures(ParameterizedPreviewMessage)]
public void Log(string level, string message, params object[] args)
{
_consoleLoggerRedirector.FormattedWriteLine(level, message, args);
}

[RequiresPreviewFeatures(ParameterizedPreviewMessage)]
public void Log(string level, Exception exception, string message, params object[] args)
{
_consoleLoggerRedirector.FormattedWriteLine(level, exception, message, args);
}
#endif
}
}
Loading

0 comments on commit d4eef2a

Please sign in to comment.