Skip to content

Instantly share code, notes, and snippets.

@roryprimrose
Created May 27, 2018 04:43
Show Gist options
  • Save roryprimrose/8e38ccf9cd85c5568f45dfa459d0aa17 to your computer and use it in GitHub Desktop.
Save roryprimrose/8e38ccf9cd85c5568f45dfa459d0aa17 to your computer and use it in GitHub Desktop.
Azure Functions with ILogger example
namespace FunctionApp1
{
using Autofac;
using Autofac.Core;
using EnsureThat;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Description;
using Microsoft.Azure.WebJobs.Host;
using Microsoft.Azure.WebJobs.Host.Config;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Reflection;
using Module = Autofac.Module;
public static class Function1
{
[FunctionName("Function1")]
public static void Run([TimerTrigger("0 */1 * * * *")]TimerInfo myTimer,
[Inject(typeof(ISomething))]ISomething something,
ILogger log)
{
log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");
var value = something.GetSomething();
log.LogInformation("Found value " + value);
}
}
public interface ISomething
{
string GetSomething();
}
public class Something : ISomething
{
private readonly ILogger _logger;
public Something(ILogger logger)
{
_logger = logger;
}
public string GetSomething()
{
_logger.LogInformation("Hey, we are doing something and dependency injection works!");
return Guid.NewGuid().ToString();
}
}
[Binding]
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)]
public class InjectAttribute : Attribute
{
public InjectAttribute(Type type)
{
Type = type;
}
public Type Type { get; }
}
public class InjectConfiguration : IExtensionConfigProvider
{
private static readonly object _syncLock = new object();
private static IContainer _container;
public void Initialize(ExtensionConfigContext context)
{
InitializeContainer(context);
context
.AddBindingRule<InjectAttribute>()
.BindToInput<dynamic>(i => _container.Resolve(i.Type));
}
private void InitializeContainer(ExtensionConfigContext context)
{
if (_container != null)
{
return;
}
lock (_syncLock)
{
if (_container != null)
{
return;
}
_container = ContainerConfig.BuildContainer(context.Config.LoggerFactory);
}
}
}
public static class ContainerConfig
{
public static IContainer BuildContainer(ILoggerFactory factory)
{
var builder = new ContainerBuilder();
var assemblyTypes = Assembly.GetExecutingAssembly().GetTypes().Where(x => x.GetInterfaces().Any()).ToArray();
builder.RegisterTypes(assemblyTypes).AsImplementedInterfaces();
builder.RegisterInstance(factory).As<ILoggerFactory>();
builder.RegisterModule<LoggerModule>();
return builder.Build();
}
}
public class LoggerModule : Module
{
private static readonly ConcurrentDictionary<Type, object> _logCache = new ConcurrentDictionary<Type, object>();
private interface ILoggerWrapper
{
object Create(ILoggerFactory factory);
}
protected override void AttachToComponentRegistration(
IComponentRegistry componentRegistry,
IComponentRegistration registration)
{
Ensure.Any.IsNotNull(registration, nameof(registration));
// Handle constructor parameters.
registration.Preparing += OnComponentPreparing;
}
private static object GetLogger(IComponentContext context, Type declaringType)
{
return _logCache.GetOrAdd(
declaringType,
x =>
{
var factory = context.Resolve<ILoggerFactory>();
var loggerName = "Function." + declaringType.FullName + ".User";
return factory.CreateLogger(loggerName);
});
}
private static void OnComponentPreparing(object sender, PreparingEventArgs e)
{
var t = e.Component.Activator.LimitType;
if (t.FullName.IndexOf(nameof(FunctionApp1), StringComparison.OrdinalIgnoreCase) == -1)
{
return;
}
if (t.FullName.EndsWith("[]", StringComparison.OrdinalIgnoreCase))
{
// Ignore IEnumerable types
return;
}
e.Parameters = e.Parameters.Union(
new[]
{
new ResolvedParameter((p, i) => p.ParameterType == typeof(ILogger), (p, i) => GetLogger(i, t))
});
}
}
}
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<AzureFunctionsVersion>v2</AzureFunctionsVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Autofac" Version="4.8.1" />
<PackageReference Include="Ensure.That" Version="8.0.0" />
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="1.0.13" />
</ItemGroup>
<ItemGroup>
<None Update="host.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="local.settings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</None>
</ItemGroup>
</Project>
@hiraldesai
Copy link

This is great! Thank you for posting. I was able to use this in one of my functions v2 app - however I have reference to more than one external libraries and I ended up removing this check from code - do you know why you'd want to explicitly check for this?

        if (t.FullName.IndexOf(nameof(FunctionApp1), StringComparison.OrdinalIgnoreCase) == -1)
        {
            return;
        }

@joaoantunes
Copy link

I wanted to try your code since I am having some issues with logging but your code is not compiling after updating the nuggets to the latests versions.

_container = ContainerConfig.BuildContainer(context.Config.LoggerFactory); line does not work with the latest Microsfot.NET.Sdk.Functions v1.0.29

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment