aws-powertools / powertools-lambda-dotnet

Powertools is a developer toolkit to implement Serverless best practices and increase developer velocity.
https://docs.powertools.aws.dev/lambda/dotnet/
MIT No Attribution
158 stars 24 forks source link

Format of JSON not as expected #230

Open bjhogan opened 1 year ago

bjhogan commented 1 year ago

Expected Behaviour

For an object Person, that has an Address I expect to see it logged like this -

When logging using Logger.LogInformation<Person>(person, "{Name} and is {Age} years old", new object[]{person.Name, person.Age}); I expect the output to look like -

"person": {
    "name": "Alan Adams",
    "age": 11,
    "address": {
        "street": "123 Main Street",
        "city": "Boston"
    }
},

Current Behaviour

Instead the output is -

"name": "Alan Adams",
"age": 11,
"address": {
    "street": "123 Main Street",
    "city": "Boston"
},

Person is lost.

Code snippet

using Amazon.Lambda.Core;
using AWS.Lambda.Powertools.Logging;

// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace ThreeSimpleWaysToLog;

public class Function

{
    [Logging(LogEvent = true, LoggerOutputCase = LoggerOutputCase.CamelCase)]
    public void FunctionHandler(string input, ILambdaContext context)
    {
        Person person = new Person { Name ="Alan Adams", Age = 11, Address = new Address{ Street = "123 Main Street",  City ="Boston" } };
        Logger.LogInformation<Person>(person, "{Name} and is {Age} years old", new object[]{person.Name, person.Age});

    }
}

public class Person 
{
    public string Name {get ; set;} 
    public int Age { get; set; }
    public Address Address { get; set; }
}
public class Address 
{
    public string Street { get; set; }
    public string City { get; set; }
}

Possible Solution

I would expect the log out to look the same as it does when using like this -

Logger.AppendKey("Person", person);
Logger.LogInformation("{Name} and is {Age} years old", new object[]{person.Name, person.Age});
Logger.RemoveKeys("Person");

The output from this is -

{
    "coldStart": true,
    "xrayTraceId": "1-642b077d-0e615d154a66119a5585838b",
    "person": {
        "name": "Alan Adams",
        "age": 11,
        "address": {
            "street": "123 Main Street",
            "city": "Boston"
        }
    },
    "functionName": "ThreeSimpleWaysToLog",
    "functionVersion": "$LATEST",
    "functionMemorySize": 256,
    "functionArn": "arn:aws:lambda:us-east-1:694977046108:function:ThreeSimpleWaysToLog",
    "functionRequestId": "5bf50f21-2c0e-4327-82df-fd0939bf6aa5",
    "timestamp": "2023-04-03T17:06:07.0296164Z",
    "level": "Information",
    "service": "ThreeSimpleWaysToLog",
    "name": "AWS.Lambda.Powertools.Logging.Logger",
    "message": "Alan Adams and is 11 years old"
}

The Person is clearly shown.

Steps to Reproduce

Deploy the code provided and invoke.

AWS Lambda Powertools for .NET version

latest

AWS Lambda function runtime

dotnet6

Debugging logs

No response

hjgraca commented 1 year ago

@bjhogan thanks for reporting. Having a look

sliedig commented 1 year ago

Related to #116

amirkaws commented 1 year ago

Hi @bjhogan, thanks for opening the issue. The extraKeys parameter in Logger.LogInformation(extraKeys, "message"), expect dictionary or a list of key/value pairs. So the object also be treated as a bag of key/value pair and will be logged in the root level. You can pass "person" object as value in combination with the key name to achieve the desired outcome.

var extraKeys = new { Person = person };
Logger.LogInformation(extraKeys, $"{person.Name} and is {person.Age} years old");

On a separate notes, we have already another issue https://github.com/awslabs/aws-lambda-powertools-dotnet/issues/166 to improve the documentation.