How can I set securityContext for log4net programmatically? - c#

I am trying to set log4net securitycontext programmatically in the global.asax, but it doesn´t work. If I put this key in the web.config it works great, but i want to take those values from the database.
My web.config that works:
<log4net>
<appender name="FileAppenderGeneral" type="log4net.Appender.RollingFileAppender">
<param name="File" value="Logs\app.log" />
<appendToFile value="true" />
<rollingStyle value="Date" />
<datePattern value="'.'dd" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%d %-5p - %m%n" />
</layout>
<<securityContext type="log4net.Util.WindowsSecurityContext">
<domainName value="hostname"/>
<userName value="username" />
<password value="password" />
</securityContext>
<encoding value="utf-8" />
</appender>
My global.asax that not works:
log4net.Config.XmlConfigurator.Configure();
ILog[] loggers = LogManager.GetCurrentLoggers();
foreach (ILog logger in loggers)
{
foreach (IAppender appender in logger.Logger.Repository.GetAppenders())
{
if (appender.GetType() == typeof(RollingFileAppender))
{
log4net.Appender.RollingFileAppender fileAppender = (RollingFileAppender)appender;
WindowsSecurityContext securityContext = new log4net.Util.WindowsSecurityContext();
securityContext.DomainName = "hostname";
securityContext.UserName = "username";
securityContext.Password = "password";
securityContext.ActivateOptions();
fileAppender.SecurityContext = securityContext;
}
}
}
Any idea what am I doing bad in the global.asax?

I would say that you need to create your own appender.
The log4net configuration file is just config for each logger that will be used in your applications. It means that you will need to 'programmatically' change security context for all your loggers. But here is a problem. You don't have all your loggers at the start of your application.
Therefore, you need to create your own appender and inherit it from the appender that you need. That's the only way to inject your own logic in log4net behavior.

Related

How to filter log records in an application?

I have a WinForms application with log4net.
The app.config has a log4net configuration section. It contains settings like this:
<appender name="coloredConsoleAppender" type="log4net.Appender.ColoredConsoleAppender">
<filter type="log4net.Filter.LevelRangeFilter">
<levelMin value="INFO" />
<levelMax value="FATAL" />
</filter>
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%d [%t] %m%n" />
</layout>
</appender>
But user wants to change levelMin and levelMax via GUI menu because edit app.config file is not comfortable.
How can I change the levelMin and levelMax values in application?
log4net can be configured by config file and later the application can correct parameters like this:
Hierarchy hierarchy = (Hierarchy)LogManager.GetRepository();
hierarchy.Root.Level = Level.Error;
hierarchy.Configured = true;

How to create new log4net every day if service running continuously from many days

I have implemented log4net in my windows service and it works as expected and created new file with current date as per config setting.
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,Log4net" />
</configSections>
<log4net>
<appender name="file" type="log4net.Appender.RollingFileAppender">
<file type="log4net.Util.PatternString" value="Logs\log-%utcdate{yyyy-MM-dd}.txt" />
<staticLogFileName value="false" />
<appendToFile value="true" />
<rollingStyle value="Composite" />
<maxSizeRollBackups value="5" />
<maximumFileSize value="5MB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %level %logger - %message%newline" />
</layout>
<param name="DatePattern" value="dd.MM.yyyy'.log'" />
</appender>
<root>
<level value="ALL" />
<appender-ref ref="file" />
</root>
</log4net>
Problem here is that, if my service is running from last 2 days, so it will not create new file with current date it keep reference of 2 days older file and adding logs into older file instead of create new file for that day.
Logger code is like
public static class Logger
{
public static log4net.ILog Log { get; set; }
static Logger()
{
Log = log4net.LogManager.GetLogger(typeof(System.Reflection.MethodBase));
}
public static void Trace(string message)
{
Log.Info(message);
}
public static void LogException(Exception ex)
{
StringBuilder builer = new StringBuilder();
builer.AppendLine("=============Exception===========");
builer.AppendLine("Exception: {0}");
builer.AppendLine("StackTrack: {1}");
Log.ErrorFormat(builer.ToString(), ex.Message, ex.StackTrace);
}
}
To log info into log file I am using code
Logger.Trace("Hello");
What is code level changes require for me to, create new log file every day even service/desktop application is running continuously from last many days?
Your configuration has both <staticLogFileName value="false" /> and <staticLogFileName value="true" />, which is may explain why it's not rolling correctly.
I suggest that you remove the <staticLogFileName value="true" /> and change the file and DatePattern as follows:
<file value="Logs\log-" />
...
<param name="DatePattern" value="yyyy-MM-dd'.log'" />
With staticLogFileName false, the date string will be appended to the base file name to give e.g.:
Logs\log-2018-01-30.log
I would note however that log4net will only check if it needs to roll the log file when you actually log a message, so if you aren't logging frequently, it may not roll the moment the next day begins.

Configure Log4Net for the full project

I have the following code which Logs everything very nicely. Am I going to have to add this to the constructor of all of my classes?
Is there anyway to configure it for the full project? I suppose I could pass log around to all of the classes but that seams like a messy solution.
class Program
{
/// <summary>
/// Application start
/// <param name="settings"></param>
/// <returns></returns>
static int Main(string[] args)
{
string logFile = string.Format(#"{0}\Cloud\Cloud.Log", Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData));
log4net.GlobalContext.Properties["LogFileName"] = logFile;
log4net.Config.XmlConfigurator.Configure();
ILog log = log4net.LogManager.GetLogger(typeof(Program));
log.Info("Console Applicatin Start");
}
}
How should can I configure Log4Net for the full solution?
I didn't think it was relevant to the question but here is my my App.config:
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<log4net>
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file type="log4net.Util.PatternString" value="%property{LogFileName}.txt" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="250KB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
</layout>
</appender>
<root>
<level value="ALL" />
<appender-ref ref="RollingFileAppender" />
</root>
</log4net>
I usually use a wrapper class. Something like:
public class Logger
{
private static readonly log4net.ILog _log = log4net.LogManager.GetLogger(typeof(Logger));
static Logger()
{
log4net.Config.XmlConfigurator.Configure();
}
public void Error(string format, params object[] args)
{
_log.Error(string.Format(format, args));
}
//...
}
And then just instantiate that where I need it. Like:
private Logger _log = new Logger();
And the use it like:
_log.Error("Something went wrong, Exception: {0}, More parameters: {1}",
e.Message, "Another parameter");
The
log4net.Config.XmlConfigurator.Configure();
Should configure log4net according to your app.config.
Edit:
I thought I'd post my log4net config, in case you want to try one that has been confirmed working. It sets up a file logger and a console logger (useful to see logging i development environment):
<log4net>
<root>
<level value="ALL" />
<appender-ref ref="ConsoleAppender" />
<appender-ref ref="DebugFileLogger" />
</root>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger: %message%newline" />
</layout>
</appender>
<appender name="DebugFileLogger" type="log4net.Appender.RollingFileAppender">
<param name="File" value="Logs/DebugLog.log" />
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="20MB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%d%t %m%n" />
</layout>
</appender>
</log4net>
One of the great features of log4net is the ability to configure filtering and processing differently depending on the logger name: any solution that wraps the logger in a wrapper, singleton or static object loses that as all logs will use the same logger name - and the useful ability to immediately see what class a log entry came from.
All you need in a class where you want to log is a field, eg:
private static ILog Log =
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
which sets the logger name to the name of the type it's contained in.
The solution I see most often, is to create a LogManager class, and a property in each class to fetch an instance of a logger, so this is the only lines of code needed in each class to get a logger:
private ILog _log;
public ILog Log
{
get { return _log ?? (_log = LogManager.GetLogger(LogName.WebServices)); }
}
The LogName.WebServices is an Enum value, and should be extended with more values, so you are able to filter your logs even more.

Log4net use the same appender config in xml to log to multiple files

I have in my config this appender:
appender name="TC3DataLogger" type="Intel.STHI.Device.ContextLog.TC3DataLogger" >
<file value="null" />
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<appendToFile value="true" />
<rollingStyle value="Once" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="100MB" />
<datePattern value="-yyyyMMdd-HHmm" />
<layout type="log4net.Layout.PatternLayout">
<header value="Date, CS, FeedbackInput, PWM_Duty_Cycle (Cold='-' Hot='+')
"/>
<conversionPattern value="%date{yyyy-MM-dd HH:mm:ss}, %message%newline" />
</layout>
<filter type="log4net.Filter.LoggerMatchFilter">
<acceptOnMatch value="true" />
<LoggerToMatch value="Intel.STHI.Device.ContextLog.TC3DataLogger" />
</filter>
<filter type="log4net.Filter.DenyAllFilter" />
</appender>
I need to simultaneously log to multiple files. I create each log file this way:
public void CreateNewLogFile(string FileName)
{
IAppender[] appenders = LogManager.GetLogger(TC3Logger.GetType()).Logger.Repository.GetAppenders();
foreach (TC3DataLogger rfa in appenders.OfType<TC3DataLogger>())
{
rfa.File = FileName;
rfa.MaxFileSize = MaxFileSizeKB;
//sub system that the configuration for this appender has changed.
rfa.ActivateOptions();
TC3datalogRFA = rfa;
}
}
Now every time I create a new log file, all my other loggers, log to this file. How can I simultaneously log to the different files?
I tried this:
public void WriteToLog(int CSNum, string Message, string LogfileName)
{
if (!TC3LogsDictionary[CSNum].Logging) return;
TC3LogsDictionary[CSNum].TC3datalogRFA.File = TC3LogsDictionary[CSNum].LogFileName;
TC3LogsDictionary[CSNum].TC3datalogRFA.ActivateOptions();
TC3LogsDictionary[CSNum].TC3Logger.Info(CSNum, Message);
}
But I get new files every time I try to log to the files.
The ability to log to different files would be a feature of a specific appender. You seem to be using some kind of custom appender and I have no idea whether this appender has that feature. I don't think either of the standard log4net file appenders can do this. You could create your own appender by creating a class that inherits from Log4net.Appender.AppenderSkeleton there is a tutorial here that gives an example of how to do it.

log4net - different log-files for assembly

I have a application which is loading PlugIn-Modules with reflection.
The Application is defining a log4net-log-appender in the app.config like:
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="logs\xxx.log" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="1MB" />
<staticLogFileName value="true" />
<threshold value="DEBUG" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger{2} - %message%newline" />
</layout>
</appender>
I get the Logger in the code like:
private static readonly ILog log = LogManager.GetLogger(typeof(Indexer));
Now, I am searching a way to declare different Log-Files for each Module (assembly), which is loaded as PlugIn with reflection.
The first problem is, that the modules are using Business-Library-Classes together (they are in a assembly which is used of all modules) which also generates log-entries. This entries should also be inserted in the log-file of the module.
The second problem is, I don't know the modules at developing-time. So I cannot insert some config in the app.config.
The second problem is, i don't know the modules at developing-time. So i cannot insert some config in the app.config.
This reveals that it might not be possible in the config file. When you add a new plugin, you can add code to add a new appender for the plugin.
Hers some (code) to get you inspired:
// Setup RollingFileAppender
log4net.Appender.RollingFileAppender fileAppender = new log4net.Appender.RollingFileAppender();
fileAppender.Layout = new log4net.Layout.PatternLayout("%d [%t]%-5p %c [%x] - %m%n");
fileAppender.MaximumFileSize = "100KB";
fileAppender.MaxSizeRollBackups = 5;
fileAppender.RollingStyle = log4net.Appender.RollingFileAppender.RollingMode.Size;
fileAppender.AppendToFile = true;
fileAppender.File = fileName;
fileAppender.Name = "XXXRollingFileAppender";
log4net.Config.BasicConfigurator.Configure(fileAppender);
You need to add that it is only from the plugin-assembly you want to log, and maybe omit them from the already configures RollingFileAppender.

Categories