microsoft-logging icon indicating copy to clipboard operation
microsoft-logging copied to clipboard

Could we make it optional to provide a ILoggerFactory and resolve it?

Open pksorensen opened this issue 7 years ago • 5 comments

My usecase is that the ILoggerFactory is build as part of startup and I want to lazy create it until the first ILogger is needed.

I modified the extension

public class LoggingExtension : UnityContainerExtension,
                                   IBuildPlanCreatorPolicy,
                                   IBuildPlanPolicy
    {
        #region Fields

        private readonly MethodInfo _createLoggerMethod = typeof(LoggingExtension).GetTypeInfo()
                                                                                  .GetDeclaredMethod(nameof(CreateLogger));

        #endregion


        #region Constructors

        //[InjectionConstructor]
        //public LoggingExtension()
        //{
        //    LoggerFactory = new LoggerFactory();
        //}

        //public LoggingExtension(ILoggerFactory factory)
        //{
        //    LoggerFactory = factory ?? new LoggerFactory();
        //}


        #endregion


        #region Public Members

        //public ILoggerFactory LoggerFactory { get; }

        #endregion


        #region IBuildPlanPolicy


        public void BuildUp(IBuilderContext context)
        {    
            context.Existing = null == context.ParentContext
                             ? context.ParentContext.Container.Resolve<ILoggerFactory>().CreateLogger(context.OriginalBuildKey.Name ?? string.Empty)
                             : context.Container.Resolve<ILoggerFactory>().CreateLogger(context.ParentContext.BuildKey.Type);
            context.BuildComplete = true;
        }

        #endregion


        #region IBuildPlanCreatorPolicy

        IBuildPlanPolicy IBuildPlanCreatorPolicy.CreatePlan(IBuilderContext context, INamedType buildKey)
        {
            var info = (context ?? throw new ArgumentNullException(nameof(context))).BuildKey
                                                                                    .Type
                                                                                    .GetTypeInfo();
            if (!info.IsGenericType) return this;

            var buildMethod = _createLoggerMethod.MakeGenericMethod(info.GenericTypeArguments.First())
                                                 .CreateDelegate(typeof(DynamicBuildPlanMethod));

            return new DynamicMethodBuildPlan((DynamicBuildPlanMethod)buildMethod, context.Container.Resolve<ILoggerFactory>());
        }

        #endregion


        #region Implementation

        private static void CreateLogger<T>(IBuilderContext context, ILoggerFactory loggerFactory)
        {
            context.Existing = loggerFactory.CreateLogger<T>();
            context.BuildComplete = true;
        }

        protected override void Initialize()
        {
            Context.Policies.Set(typeof(ILogger), string.Empty, typeof(IBuildPlanPolicy), this);
            Context.Policies.Set<IBuildPlanCreatorPolicy>(this, typeof(ILogger));
            Context.Policies.Set<IBuildPlanCreatorPolicy>(this, typeof(ILogger<>));
        }

        private delegate void DynamicBuildPlanMethod(IBuilderContext context, ILoggerFactory loggerFactory);

        private class DynamicMethodBuildPlan : IBuildPlanPolicy
        {
            private readonly DynamicBuildPlanMethod _buildMethod;
            private readonly ILoggerFactory _loggerFactory;

            /// <summary>
            /// 
            /// </summary>
            /// <param name="buildMethod"></param>
            /// <param name="loggerFactory"></param>
            public DynamicMethodBuildPlan(DynamicBuildPlanMethod buildMethod,
                                          ILoggerFactory loggerFactory)
            {
                _buildMethod = buildMethod;
                _loggerFactory = loggerFactory;
            }

            /// <summary>
            /// 
            /// </summary>
            /// <param name="context"></param>
            public void BuildUp(IBuilderContext context)
            {
                _buildMethod(context, _loggerFactory);
            }
        }

        #endregion
    }

What do you think, should we consider resolving it instead of giving it when constructing the extension?

pksorensen avatar Sep 16 '18 10:09 pksorensen

I would rather have it as Lazy<ILoggerFactory> but otherwise I like your idea.

ENikS avatar Sep 16 '18 14:09 ENikS

how would that work? My case is that the container already have a registration for ILoggerFactory.

Should i then add one extra registration for Lazy<ILoggerFactory> => InjectionFactory((c)=> new Lazy(c.resolve<ILoggerFactory>()).

Feels like i am missing something.

pksorensen avatar Sep 16 '18 14:09 pksorensen

Resolving ILoggerFactroy is slow

ENikS avatar Sep 16 '18 15:09 ENikS

It could be something like this:

[InjectionConstructor]
public LoggingExtension()
{
    _loggerFactory = new Lazy<ILoggerFactory>(() => new LoggerFactory());
}
...

Also, user should be able to provide his own instance of ILoggerFactory

ENikS avatar Sep 16 '18 15:09 ENikS

public class MyLoggerFactory : ILoggerFactory
{
    public MyLoggerFactory(IEnumerable<ILoggerFactoryPlugin> plugins){

    }

}


var container = new UnityContainer();


container.RegisterType<ILoggerFactory,MyLoggerFactory>();

container.AddNewExtension<LoggingExtension>();

container.RegisterType<ILoggerFactoryPlugin,MyPlugin>();

var logger = container.resolve<ILogger<Test>>();

I dont understand how your example will work with the given example here. The container knows about ILoggerFactory and it cannot be created at the time of adding the logging extension.

pksorensen avatar Sep 16 '18 17:09 pksorensen