ASP.NET Core Web API : how to write logs for each users separately using Log4Net?

50 Views Asked by At

I need to know how to write log for each logged in users separately.

For example USER A, then the file should be created as logs/USER A/06.02.2024.log.

I am using Log4Net to write logs to file. Please support.

I need to write custom logging for each user's separately. I tried the below code, but file not created.

 public class Log4NetLogger : ILogger
 {
     private readonly ILog _logger;

 public Log4NetLogger(ILog logger)
 {
     _logger = logger;
 }

 public IDisposable BeginScope<TState>(TState state)
 {
     return null; // No scope support in log4net
 }

 public bool IsEnabled(LogLevel logLevel)
 {
     switch (logLevel)
     {
         case LogLevel.Trace:
         case LogLevel.Debug:
             return _logger.IsDebugEnabled;
         case LogLevel.Information:
             return _logger.IsInfoEnabled;
         case LogLevel.Warning:
             return _logger.IsWarnEnabled;
         case LogLevel.Error:
             return _logger.IsErrorEnabled;
         case LogLevel.Critical:
             return _logger.IsFatalEnabled;
         default:
             throw new ArgumentOutOfRangeException(nameof(logLevel), logLevel, null);
     }
 }

 public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception,
     Func<TState, Exception, string> formatter)
 {
     if (!IsEnabled(logLevel))
     {
         return;
     }

     var message = formatter(state, exception);
     if (string.IsNullOrWhiteSpace(message))
     {
         return;
     }

     switch (logLevel)
     {
         case LogLevel.Trace:
         case LogLevel.Debug:
             _logger.Debug(message);
             break;
         case LogLevel.Information:
             _logger.Info(message);
             break;
         case LogLevel.Warning:
             _logger.Warn(message);
             break;
         case LogLevel.Error:
             _logger.Error(message, exception);
             break;
         case LogLevel.Critical:
             _logger.Fatal(message, exception);
             break;
         default:
             _logger.Warn($"Encountered unknown log level {logLevel}, writing out as Info.");
             _logger.Info(message, exception);
             break;
     }
 }
 }
}

And the custom class

public class CustomLoggerFactory : ILoggerFactory
    {
        private readonly IHttpContextAccessor _httpContextAccessor;

    public CustomLoggerFactory(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    public void AddProvider(ILoggerProvider provider)
    {
        // Do nothing or implement as needed
    }

    public ILogger CreateLogger(string categoryName)
    {
        var logger = LogManager.GetLogger(categoryName);

        var user = _httpContextAccessor.HttpContext?.User;
        if (user != null && user.Identity.IsAuthenticated)
        {
            var userId = user.FindFirst(ClaimTypes.NameIdentifier)?.Value;
            if (!string.IsNullOrEmpty(userId))
            {
                var logFilePath = $"logs/{userId}/log.txt";
                var logFolder = Path.GetDirectoryName(logFilePath);
                if (!Directory.Exists(logFolder))
                {
                    Directory.CreateDirectory(logFolder);
                }
                // Configure log4net to use the dynamic file path
                GlobalContext.Properties["LogFileName"] = logFilePath;
            }
        }

        return new Log4NetLogger(logger);
    }

    public void Dispose()
    {
        // Dispose resources if needed
    }
}

And in startup

public static void ConfigureLogging(ILoggingBuilder loggingBuilder)
{
    loggingBuilder.ClearProviders();
    loggingBuilder.AddLog4Net();
    loggingBuilder.Services.AddSingleton<ILoggerFactory, CustomLoggerFactory>();
}
0

There are 0 best solutions below