Azure Function logging using TraceWriter in external library
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();
}
}
}
As an update, Azure Functions now support consuming an ILogger
instead of TraceWriter
so you could consume any logging framework that implements ILogger
.
See the GitHub issue and the subsequent wiki documentation.
If I am correct the necessary versions for getting ILogger to work with Azure functions would be Microsoft.Azure.WebJobs 2.1.0-beta1. However, I can't seem to get an Azure function running using an ILogger instead of a TraceWriter.
Also very little information and documentation is available about developing Azure Functions using ILogger. Does anyone have more information or tips to get this working?
My C# code snippet:
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.ServiceBus;
using System;
using Newtonsoft.Json;
using Microsoft.Extensions.Logging;
namespace Experimental.Functions
{
public static class ListenToEventFunction
{
[FunctionName("ListenToEventFunction")]
public static void Run([EventHubTrigger("events", Connection = "EventHubConnectionString")]string myEventHubMessage, ILogger log)
{
log.LogInformation($"C# Event Hub trigger function processed a message: {myEventHubMessage}");
}
}
}
I get the following error when debugging my Azure Function using the Azure Function Tools for VS2017:
A ScriptHost error has occurred
Microsoft.Azure.WebJobs.Host: Error indexing method 'Functions.EnrichTelemetryLocation'.
Microsoft.Azure.WebJobs.Host: Cannot bind parameter 'log' to type ILogger.
Make sure the parameter Type is supported by the binding.
If you're using binding extensions (e.g. ServiceBus, Timers, etc.) make sure you've called the registration method for the extension(s) in your startup code (e.g. config.UseServiceBus(), config.UseTimers(), etc.).