0
votes

I have created a Blob Trigger Azure Function, and I wanted to be able to create mail alerts when I have an exception, and among the information sent in the mail alert, there should be the name of the file the exception occurred on.

I noticed that exceptions are automatically logged in Azure, but I found no way of customizing the message or the information sent along the exception. So I decided to inject a telemetry service in my Function App, and add the file name as a custom property, as you can see in the code below :

public class Function1
{
    private readonly IGremlinService _gremlinService;
    private readonly TelemetryClient _telemetryClient;
    public Function1(IGremlinService gremlinService, TelemetryConfiguration telemetryConfiguration)
    {
        this._gremlinService = gremlinService;
        this._telemetryClient = new TelemetryClient(telemetryConfiguration);
    }

    [FunctionName(nameof(Function1))]
    public async Task Run([BlobTrigger("files/{directory}/{name}.00.pdf", Connection = "AzureWebJobsStorage")] Stream myBlob, string name, ILogger logger)
    {
        try
        {
             //some code not related to the issue
        }
        catch (Exception e)
        {
            var properties = new Dictionary<string, string>
                {{"Filename", name}};
            _telemetryClient.TrackException(e, properties);
            if (e is ResponseException)
            {
                ResponseException re = (ResponseException) e;

                var statusCode = (long) re.StatusAttributes["x-ms-status-code"];
               
                _telemetryClient.TrackTrace("Error on file " + name + ". Status code: " + statusCode + " " + re.StackTrace, SeverityLevel.Error, properties);
            }
            else
            {
                _telemetryClient.TrackTrace("Error on file " + name, SeverityLevel.Error, properties);
            }
            throw;
        }
    }
}
  }   

But I still cannot customize the message to provide the user with additional information. I know I can send alerts on trace messages instead, and send customized messages this way, and this is currently what I'm doing, but I would find it cleaner to send alert on exceptions.

My second issue is that my exceptions are still logged automatically on top of being logged by the telemetry service, and for some reason I can't understand, they are logged twice, as you can see in the screenshot below from Application Insights :

enter image description here

Is there a way I can turn off the automatic logging of exceptions ? Or is there a way to customize these exceptions messages that I'm not aware of, instead of using the telemetry service ?

1
I've answered your question. Summary is to use ILogger with structure logging and with that you can log all the relevant parameters without having TelemetryClient .user1672994

1 Answers

1
votes

I believe, the 3 exceptions are being logged due to following reasons:

  1. The implementation service of IGremlinService throwing exception which is being logged.
  2. You are logging via _telemetryClient.TrackException(e, properties);
  3. Azure infrastructure is handling when throw is invoked.

Now coming to your question

I found no way of customizing the message or the information sent along the exception

I would suggest you to use ILogger for LogException and use BeginScope (read here) to define the scope properties which will be logged as Custom Properties in application insights for all the logs which are invoked during the lifetime of created scope.

Using the ILogger object, your code will be simplified as follows and all traces and exceptions inside scope will have FileName as custom property in application insights.

[FunctionName(nameof(Function1))]
public async Task Run([BlobTrigger("files/{directory}/{name}.00.pdf", Connection = "AzureWebJobsStorage")] Stream myBlob, string name, ILogger logger)
{
    using (logger.BeginScope(new Dictionary<string, object>()
    {
            ["FileName"] = name,
     }))
     {
        try
        {
             //some code not related to the issue
        }
        catch (Exception e)
        {
            logger.LogError(e, "Error occurred with {StatusCode}", (long) re.StatusAttributes["x-ms-status-code"]);
            throw;
        }
    }
}

Following summarizes the definition of statement logger.LogException(e, "Error occurred with {StatusCode}", (long) re.StatusAttributes["x-ms-status-code"]);

  1. e represents the actual exception which occurred.
  2. the code part {StatusCode} will be logged the StatusCode as Custom Property in application insights for the logged exception so you don't need to create any dictionary.
  3. FileName will be logged as Custom property as defined by Scope.

You can view a sample implementation at here.