3

I have a multi-tenant application in ASP.NET MVC 5 that can accept client logins from multiple companies. Currently, I'm using log4net to log to files, but it places all the logs from all the companies in one file. Ideally, I would like to separate out the log files so that the logs for each company resides in its own folder.

I see from this question that I can programmatically create additional appenders, which then can log to different log files. But that would mean that for each instance of a class, I would have to keep calling

ILog log = LogManager.GetLogger("CompanyA");

to get the correct logger, right? Is there a better way to do so? I'm also open to using another logger if need be.

Thanks.

Community
  • 1
  • 1
Ionian316
  • 2,303
  • 2
  • 28
  • 36

1 Answers1

3

Do you use an Ioc container in your application? I was able to solve a similar problem using AutoFac MultitenantContainer. Steps that you need to follow

  1. define the strategy you would use to identify each tenant.
  2. Register a generic logger interface with Autofac container
  3. For each tenant register specific logger.

your code could look like (extract from Autofac wiki)

    var tenantIdStrategy = new RequestParameterTenantIdentificationStrategy("tenant");
    var builder = new ContainerBuilder();
    builder.RegisterType<BaseDependency>().As<IDependency>();

    // If you have tenant-specific controllers in the same assembly as the
    // application, you should register controllers individually.
    builder.RegisterType<HomeController>();

    // Create the multitenant container and the tenant overrides.
    var mtc = new MultitenantContainer(tenantIdStrategy, builder.Build());
    mtc.ConfigureTenant("CompanyA",
       b =>
        {
          b.RegisterType<Tenant1Dependency>().As<IDependency>().InstancePerDependency();
          b.RegisterType<Tenant1Controller>().As<HomeController>();
        });

If this is the only instance where you need to differentiate the tenants and do not want to Ioc at this point you could create the factory like

static class LogFactory
{
    public static ILog GetLogger()
    {
        var requestUri = HttpContext.Current.Request.Url.AbsoluteUri;
        switch (requestUri)
        {
            case "companyA.domain.com":
                return LogManager.GetLogger("CompanyA");
            case "companyB.domain.com":
                return LogManager.GetLogger("CompanyB");
            default:
                return LogManager.GetLogger("default");
        }
    }
}

now use the factory instead of directly using Logmanager

 ILog logger = LogFactory.GetLogger();
  • No, I'm not using an IoC container right now. I'll look into AutoFac in the future. Is there a way to do the logging without it? – Ionian316 May 20 '14 at 17:44
  • I could think of using a factory that will return the logger. Within the factory have a logic that will return the logger based on request Url if you specific Url per tenant. When I started with mutitenant application I had few requirements of specific behavior per tenant which only grew over time. if you are looking at implementing this as non functional requirement and not just for logging then I would encourage looking at Autofac. – Kamalakar Nellipudi May 20 '14 at 20:24
  • Wow, that's extremely cool. I'm using Unity and it is not quite this easy to do things on a per-tenant basis. – Casey Aug 04 '14 at 20:56