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?

  • What do you want as result ? – Hury Shen Mar 25 '21 at 08:31
  • I want the same result between Test2 and Test3. Like in this example => https://github.com/messagetemplates/messagetemplates-csharp I thought that this would be the default templating of the .Net Core Logger – Martin Oehlert Mar 25 '21 at 08:39
  • Does this code: `log.LogInformation("Test1: {$Test}", JsonConvert.SerializeObject(instance));` meet your requirement ? – Hury Shen Mar 25 '21 at 08:43
  • Yes, this would work, but i thought that this kind of behavior is implemented in the default logger. – Martin Oehlert Mar 25 '21 at 08: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. – user1672994 Mar 25 '21 at 09:29
  • I thought of this because it is stated so on this site => https://messagetemplates.org/ but maybe it is not implemented in Microsoft.Extensions.Logging. Thanks for your help. – Martin Oehlert Mar 25 '21 at 09:43

2 Answers2

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.

user1672994
  • 10,509
  • 1
  • 19
  • 32
  • 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 https://messagetemplates.org/ – Martin Oehlert Mar 25 '21 at 08:58
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

Cindy Pau
  • 13,085
  • 1
  • 15
  • 27