Azure Function logging using TraceWriter in external library

Lance picture Lance · Nov 2, 2016 · Viewed 21.6k times · Source

How can I reuse the TraceWriter object available in an Azure Function to log information in an externally referenced library? I tried passing in the object using the constructor and referencing the TraceWriter class (web.http.tracing). I didn't have luck as the classes seem different.

Answer

Murray Foxcroft picture Murray Foxcroft · Dec 2, 2016

Short version Use the Microsoft.Azure.WebJobs.Host.TraceWriter available in this nuget package.

Alternatively, build your functions as a Web Project and you can debug locally. You can find a sample here.

Long Version

Your problem here is that you are using the wrong TraceWriter.

I used the Azure Function logger in an Azure function to output the type of the logger.

log.Info(log.GetType().ToString());

Which gave the following:

Microsoft.Azure.WebJobs.Script.InterceptingTraceWriter

I too was expecting a Web/Http TraceWriter and was surprised that there is yet another implementation to deal with. Microsoft could really do with creating a standard approach, or at least giving us a nice clean interface for Error, Warning, Info, Verbose etc. Maybe something for .Net Standard... please.

I will create my own interface and wrap my app logger and the Azure one so that I can inject whichever I need without causing headaches further along in my code. This will also offer some protection from potential pain inflicted by future breaking changes.

Anyway, I digress, I then tracked Microsoft.Azure.WebJobs.Script.InterceptingTraceWriter down to the Azure Functions / Webjobs scripting GitHub repo and then on to the Nuget package. I have tested this and it works fine to pass the Azure Function logger in to your external assembly and continue to log to the Azure Function environment from there.

Here is an example:

using Microsoft.Azure.WebJobs.Host;

public static void TryLog(TraceWriter azureFunctionsLogger)
{
    azureFunctionsLogger.Info("************** IT WORKED **************");
}

I love the potential of Azure functions, but it is still a little immature and overly complex.

I hope this helps.

Added a very simple single class logger to illustrate.

It writes to either the Azure Functions Logger or a standard Systems.Diagnostics.Trace. You need to paste this over the contents of Program.cs of a standard C# Console Application. You will also need to include the Nuget package Microsoft.Azure.WebJobs.

namespace LoggingTestConsole
{
    using System;

    /// <summary>
    /// Generic logging interface for portability 
    /// </summary>
    public interface ILogger
    {
        void Error(string message);
        void Information(string message);
        void Warning(string message);
    }


    /// <summary>
    /// Azure Functions logger
    /// </summary>
    public class AzureFunctionLogger : ILogger
    {
        private static Microsoft.Azure.WebJobs.Host.TraceWriter _logger;

        public AzureFunctionLogger(Microsoft.Azure.WebJobs.Host.TraceWriter logger)
        {
            _logger = logger;
        }

        public void Error(string message)
        {
            _logger.Error(message);
        }

        public void Information(string message)
        {
            _logger.Info(message);
        }

        public void Warning(string message)
        {
            _logger.Warning(message);
        }
    }


    /// <summary>
    /// Windows Trace logger
    /// </summary>
    public class TraceLogger : ILogger
    {
        public TraceLogger()
        {
            System.Diagnostics.Trace.Listeners.Add(new System.Diagnostics.TextWriterTraceListener(Console.Out));
        }

        public void Error(string message)
        {
            System.Diagnostics.Trace.TraceError(message);
        }


        public void Information(string message)
        {
            System.Diagnostics.Trace.TraceInformation(message);
        }

        public void Warning(string message)
        {
            System.Diagnostics.Trace.TraceWarning(message);
        }

        public void Warning(string format, params object[] args)
        {
            System.Diagnostics.Trace.TraceWarning(format, args);
        }
    }

    /// <summary>
    /// You would put this in a separate project and just share the ILogger interface.
    /// Pass the relevant logger in from Azure Functions or a standard windows Trace logger.
    /// </summary>
    public class DoStuff
    {
        public DoStuff(ILogger logger)
        {
            logger.Information("We are logging to logger you passed in!");
        }
    }

    public class Program
    {

        /// <summary>
        /// Sample usage
        /// </summary>
        static void Main(string[] args)
        {
            // var loggerEnvironment = "AzureFunctions";
            var loggerEnvironment = "ConsoleApp";

            ILogger logger = null;

            if (loggerEnvironment == "AzureFunctions")
            {
                Microsoft.Azure.WebJobs.Host.TraceWriter azureFunctionLogger = null;
                logger = new AzureFunctionLogger(azureFunctionLogger);
            }
            else if (loggerEnvironment == "ConsoleApp")
            {
                logger = new TraceLogger();
            }

            var doStuff = new DoStuff(logger);
            Console.ReadKey();
        }
    }
}