0

i am trying to get structured logging working in a Azure Function, but it does not work on my side.

I wrote a simple application like this

[FunctionName("Dummy")]
public IActionResult Run([HttpTrigger(AuthorizationLevel.Anonymous)]HttpRequest request, ILogger log)
{
    var instance = new User
    {
        Name1 = "foo",
        Name2 = "bar"
    };
    log.LogInformation("Test1: {$Test}", instance);
    log.LogInformation("Test2: {@Name}", instance);
    log.LogInformation("Test3: {@Name}", new { Name1 = "abc", Name2 = "def" });
    log.LogInformation("Test4: {Vorname} {Nachname}", instance.Name1, instance.Name2);
    return new OkResult();
}

public class User
{
    public string Name1 { get; set; }
    public string Name2 { get; set; }
}

and the output looks like this:

Test1: Company.FunctionApp1.Function+User
Test2: Company.FunctionApp1.Function+User
Test3: { Name1 = abc, Name2 = def }
Test4: foo bar

I have no clue why the destructure is working on the dynamic type but not on the defined class. I have found many examples for normal logging with no destructure of a object, but i thought that it should work out of the box.

Am i missing something?

6
  • What do you want as result ? Commented Mar 25, 2021 at 8:31
  • I want the same result between Test2 and Test3. Like in this example => github.com/messagetemplates/messagetemplates-csharp I thought that this would be the default templating of the .Net Core Logger Commented Mar 25, 2021 at 8:39
  • Does this code: log.LogInformation("Test1: {$Test}", JsonConvert.SerializeObject(instance)); meet your requirement ? Commented Mar 25, 2021 at 8:43
  • Yes, this would work, but i thought that this kind of behavior is implemented in the default logger. Commented Mar 25, 2021 at 8:59
  • I'm not sure if it being supported by Application Insights provider. Note - SeriLog provide destructuring the object while logging. Currently the workaround can be for you is to define the ToString on User object. Or you can write an extension method which can use the reflection to destructure the object. Commented Mar 25, 2021 at 9:29

2 Answers 2

0

Test 3 is printing as { Name1 = abc, Name2 = def } as the type defined is as anonymous object for which compiler generates the ToString() method to return a string with property and value mapping.

Check in this discussion.

You can validate the same by decompiling.

Since, Test2 and Test1 uses object and for which there is no override ToString() definition that's why the TypeName is returned.

The right way would be to go with Test4 so that Vorname and Nachname are logged as custom property and can be used to filter.

Sign up to request clarification or add additional context in comments.

1 Comment

Good point with the dynamic type, i have missed this. I do want it to be as custom properties in application insights. And it does work with the JsonConvert.SerializeObject, but in my opinion it should work out of the box with the @ in front of the name. I thought that the default implementation is according to this messagetemplates.org
0

user1672994's answer is right, you can do something like below:

using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;

namespace FunctionApp96
{
    public static class Function1
    {
        [FunctionName("Function1")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            var instance = new User
            {
                Name1 = "foo",
                Name2 = "bar"
            };
            log.LogInformation("Test1: {$Test}", instance);
            log.LogInformation("Test2: {@Name}", instance);
            log.LogInformation("Test3: {@Name}", new { Name1 = "abc", Name2 = "def" });
            log.LogInformation("Test4: {Vorname} {Nachname}", instance.Name1, instance.Name2);
            return new OkObjectResult("");
        }
    }
    public class User
    {
        public override string ToString()
        {
            string str = "{ Name1 = " + Name1 + ", Name2 =" + Name2 + " }";
            return str;
        }
        public string Name1 { get; set; }
        public string Name2 { get; set; }
    }
}

And you will get:

enter image description here

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.