-
Notifications
You must be signed in to change notification settings - Fork 478
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
Initial PR for structured logging support #1588
Initial PR for structured logging support #1588
Conversation
…ent new JSON structured log formatter in Amazon.Lambda.RuntimeSupport
{ | ||
_writer.WriteLine(message); | ||
_writer.WriteLine(exception.ToString()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
null check needed ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
@@ -107,7 +128,7 @@ public class LogLevelLoggerWriter : IConsoleLoggerWriter | |||
/// Amazon.Lambda.Core can not be relied on because the Lambda Function could be using | |||
/// an older version of Amazon.Lambda.Core before LogLevel existed in Amazon.Lambda.Core. | |||
/// </summary> | |||
enum LogLevel | |||
public enum LogLevel |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are we making it public for user to use ? if it's internal to package, can we live with internal ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't need to be public. Users interact with the LogLevel
enum from Amazon.Lambda.Core. RuntimeSupport has to have a mirror of this enum because it can't rely on having the latest copy of Amazon.Lambda.Core when running that would have the enum.
using System.Globalization; | ||
using System.Text; | ||
|
||
namespace Amazon.Lambda.RuntimeSupport.Helpers.Logging |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here are few pointers as I was scanning through the Microsoft implementations. I am suggesting to see if we can get some inspirations and the code I am referring is well tested and inside their SDK (less buggy, so my inspirations :)).
- https://source.dot.net/#Microsoft.Extensions.Logging.Abstractions/LogValuesFormatter.cs,66cbe2d145df9bc8 => This is where given a string (in our case it's a message template), it spits out various params.
- https://source.dot.net/#Microsoft.Extensions.Logging.Abstractions/FormattedLogValues.cs,b8a158d8a121f959 => it holds on to the State (in our case MessageState). The ToString method uses the formatter to generate the string
- One of the Implementation I was looking for both Json and normal logging is EventSource => https://source.dot.net/#Microsoft.Extensions.Logging.EventSource/EventSourceLogger.cs,92 , which actually adds the json values for all properties as mentioned in the req/design spec.
Libraries/src/Amazon.Lambda.RuntimeSupport/Helpers/ConsoleLoggerWriter.cs
Show resolved
Hide resolved
Libraries/src/Amazon.Lambda.RuntimeSupport/Helpers/Logging/AbstractLogMessageFormatter.cs
Show resolved
Hide resolved
Libraries/src/Amazon.Lambda.RuntimeSupport/Helpers/ConsoleLoggerWriter.cs
Show resolved
Hide resolved
Libraries/src/Amazon.Lambda.RuntimeSupport/Helpers/Logging/JsonLogMessageFormatter.cs
Outdated
Show resolved
Hide resolved
Libraries/src/Amazon.Lambda.RuntimeSupport/Helpers/Logging/MessageProperty.cs
Outdated
Show resolved
Hide resolved
/// <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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't args
be passed down to the next function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, good catch.
/// <param name="message">Message to log.</param> | ||
/// <param name="args">Values to be replaced in log messages that are parameterized.</param> | ||
[RequiresPreviewFeatures("Parameterized logging is in preview till new version of .NET Lambda runtime client is deployed to the .NET Lambda managed runtime.")] | ||
void Log(string level, Exception exception, string message, params object[] args) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment here. Not sure why args
is not being used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
Libraries/src/Amazon.Lambda.RuntimeSupport/Helpers/ConsoleLoggerWriter.cs
Show resolved
Hide resolved
/// <param name="level"></param> | ||
/// <param name="exception"></param> | ||
/// <param name="message"></param> | ||
/// <param name="args"></param> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add more docs for the params similar to ILambdaLogger
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
/// <param name="messageTemplate"></param> | ||
/// <returns></returns> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: add docs for these tags
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
/// <param name="state"></param> | ||
/// <returns></returns> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: add docs for the empty tags in this class
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
private static readonly char[] PARAM_FORMAT_DELIMITERS = { ':' }; | ||
|
||
/// <summary> | ||
/// Parse the string string representation of the message property without the brackets |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
string
is duplicated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
/// </summary> | ||
public string MessageToken { get; private set; } | ||
|
||
public enum Directive { Default, JsonSerialization }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add docs for this property
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
56ba04d
to
924b1cd
Compare
"project file to \"true\""; | ||
|
||
/// <summary> | ||
/// Log message catagorized by the given log level |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: typo in "catagorized"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
void Log(string level, string message, params object[] args) => Log(level, message, args); | ||
|
||
/// <summary> | ||
/// Log message catagorized by the given log level |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: typo in "catagorized"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
} | ||
|
||
/// <summary> | ||
/// Log message catagorized by the given log level |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: typo in "catagorized"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
void Log(LogLevel level, string message, params object[] args) => Log(level.ToString(), message, args); | ||
|
||
/// <summary> | ||
/// Log message catagorized by the given log level |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: typo in "catagorized"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
@@ -89,9 +104,18 @@ public void FormattedWriteLine(string message) | |||
_writer.WriteLine(message); | |||
} | |||
|
|||
public void FormattedWriteLine(string level, string message) | |||
public void FormattedWriteLine(string level, string message, params object[] args) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: add docs to public methods
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
_wrappedStdOutWriter.FormattedWriteLine(level, (Exception)null, message, args); | ||
} | ||
|
||
public void FormattedWriteLine(string level, Exception exception, string message, params object[] args) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: add docs to public methods
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
} | ||
else | ||
{ | ||
argument = messageArguments[propertyIndex]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please add a null check for messageArguments
before indexing into it? I got a warning for it in Rider.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added a short circuit at the top that exits out if messageArguments
is null or empty.
private static readonly UTF8Encoding UTF8NoBomNoThrow = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: false); | ||
|
||
// Options used when serializing any message property values as a JSON to be added to the structured log message. | ||
private JsonSerializerOptions _jsonSerialiazationOptions; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo in _jsonSerialiazationOptions
. should be _jsonSerializationOptions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
writer.WriteStartObject(); | ||
foreach (DictionaryEntry entry in ((IDictionary)messageArgument)) | ||
{ | ||
writer.WritePropertyName(entry.Key.ToString()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
entry.Key.ToString()
throws a possible null warning. Could you change it to entry.Key.ToString() ?? string.Empty
or something similar?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done but if key
is null by this point something has really gone wrong.
|
||
try | ||
{ | ||
var formatedValue = string.Format("{0:" + formatArgument + "}", value); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo in formatedValue
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good assuming you address @philasmar 's comments, but don't need to see again.
Description of changes:
This PR is the initial work to add support for structured logging natively in the Amazon.Lambda.RuntimeSupport the .NET Lambda runtime client (RIC). Serilog was used as the example of the experience but is not used directly so that we would not take a hard dependency on Serilog or interfere with anybody wanting to implement their own structured logging using Serilog.
Changes made:
DefaultLogMessageFormatter
formatter represents what we do today andJsonLogMessageFormatter
is the new structured logging.NOTE: The new parameterize logging methods on ILambadLogger are marked with the .NET attribute
RequiresPreviewFeatures
. This requires users that want to use these methods to have to turn on preview language features in the project file,<LangVersion>preview</LangVersion>
. This is done due to the fact thatAmazon.Lambda.Core
with these new APIs will go out before the .NET managed runtime is deployed with the version ofAmazon.Lambda.RuntimeSupport
. If users call these methods before the runtime is updated the message will be logged ignoring the parameters. For users that deploy as an executable with the latest version version ofAmazon.Lambda.RuntimeSupport
they will be able to use these methods with no problems. OnceAmazon.Lambda.RuntimeSupport
has been updated in the managed runtime a new version ofAmazon.Lambda.Core
will be released removing theRequiresPreviewFeatures
attribute.This PR uses a lot of the code ideas from PR #1323 by @dhhoang. The major difference are
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.