When I have following xml configuration to configure log4net for remotingappender, it all works.
<log4net>
<appender name="RemotingAppender" type="log4net.Appender.RemotingAppender" >
<sink value="tcp://localhost:8085/LoggingSink" />
<lossy value="false" />
<bufferSize value="1" />
<onlyFixPartialEventData value="true" />
</appender>
<root>
<level value="ALL" />
<appender-ref ref="RemotingAppender" />
</root>
</log4net>
I want to do the same thing in code. I searched a littlebit and find an example like the following. But i could not get it working.
ILog log = log4net.LogManager.GetLogger("logName");
Repository.Hierarchy.Logger l = (Repository.Hierarchy.Logger)log.Logger;
// set level
l.Level = l.Hierarchy.LevelMap["ALL"];
// create appander
Appender.RemotingAppender remotingAppender = new Appender.RemotingAppender();
remotingAppender.Name = "custom";
remotingAppender.Sink = "tcp://localhost:8085/LoggingSink";
remotingAppender.Lossy = false;
remotingAppender.BufferSize = 1;
//remotingAppender.Fix = log4net.Core.FixFlags.All;
// create pattern
log4net.Layout.PatternLayout layout = new log4net.Layout.PatternLayout();
layout.ConversionPattern = "%d [%thread] %-5p %c [%a] - %m [%line] [%M]%n";
layout.ActivateOptions();
remotingAppender.Layout = layout;
remotingAppender.ActivateOptions();
// add appender
l.AddAppender(remotingAppender);
// perform logging (doesnt work)
log.Warn("my warning");
log.Error("my error");
What is the missing side in my code?
try one of log4net.Config.BasicConfigurator.Configure(...) oveloads.
I finally get it working. i firstly load and xml configuration which is almost emptpy. Then i put the pattern layout which has same pattern string as remoting listener. My modified xml file is below:
<log4net>
<root>
<level value="ALL" />
</root>
</log4net>
And i load this configuration at the beginning of my application (program.c)
log4net.Config.XmlConfigurator.Configure(file)
Related
In App.Config I declare a config section for my console application:
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
And configure a ConsoleAppender:
<log4net>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
</layout>
</appender>
<root>
<level value="ALL" />
<appender-ref ref="ConsoleAppender" />
</root>
</log4net>
We also declare a RollingFile appender in a logging util class that's part of our standard codebase at app-startup (which is not easily modified):
_hierarchy = (Hierarchy)LogManager.GetRepository();
_rollingFileAppender = new RollingFileAppender();
... //_rollingFileppender options
_rollingFileAppender.ActivateOptions();
_hierarchy.Root.AddAppender(_rollingFileAppender);
_hierarchy.Configured = true;
When I run the application, I see log-entries are written to files as expected but nothing is written to the console.
When I inspect my ILog instance in the debugger, I see no appenders at all in Logger.Appenders but I do see the RollingFileAppender instance as the only element in Root.Appenders.
log4net is something I am used to "it just works" - is there some incompatibility having config and code add appenders, or some line I need to get LogManager to look in app.config?
You just got me curious and i decided to play around a bit.
First observations is: You are right.
After some google i found this this
App.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<log4net>
<appender name="ConsoleAppender" type="log4net.Appender.ColoredConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date %level [%thread] %logger{1} %username - %message%newline" />
</layout>
<mapping>
<level value="WARN" />
<foreColor value="Yellow, HighIntensity" />
</mapping>
<mapping>
<level value="ERROR" />
<foreColor value="Red, HighIntensity" />
</mapping>
</appender>
<root>
<level value="ALL" />
<appender-ref ref="ConsoleAppender" />
</root>
</log4net>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
</configuration>
Setup
using log4net;
using log4net.Appender;
using log4net.Layout;
using log4net.Repository.Hierarchy;
namespace LoggerDemo
{
public static class Program
{
private static readonly ILog Logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
public static void Main(string[] args)
{
SetupFileAppender();
SetupTraceAppender();
Logger.Error("Error");
}
private static void SetupTraceAppender()
{
var patternLayout = new PatternLayout();
patternLayout.ConversionPattern = "%date [%thread] %-5level %logger - %message%newline";
patternLayout.ActivateOptions();
var trace = new TraceAppender();
trace.Layout = patternLayout;
trace.ActivateOptions();
var l = (Logger)Logger.Logger;
l.AddAppender(trace);
}
private static void SetupFileAppender()
{
var patternLayout = new PatternLayout();
patternLayout.ConversionPattern = "%date [%thread] %-5level %logger - %message%newline";
patternLayout.ActivateOptions();
var roller = new RollingFileAppender();
roller.AppendToFile = true;
roller.File = "Log.txt";
roller.Layout = patternLayout;
roller.MaxSizeRollBackups = 5;
roller.RollingStyle = RollingFileAppender.RollingMode.Size;
roller.StaticLogFileName = true;
roller.ActivateOptions();
var l = (Logger)Logger.Logger;
l.AddAppender(roller);
}
}
}
Most Important
In your AssemblyInfo add [assembly: log4net.Config.XmlConfigurator(Watch = true)]
Result
I looked in google about log4net and seems interesting. I looked into some website and
for the output here should be something like log4net.config i guess? The guy showed to press it and in the Properties here should be "Copy to Output Directory": "Copy Always".
Maybe you can somehow figure to use it and print into the console the output. Here is really useful information in google about it you can click Here to read more.
Hope i somehow helped you :)
Is there a way to make the name of the fileAppender variable?
I.e. when I call an action on my controller which takes an object, I would like to write this to a log file.
The name of the file would look something like :
yyyyMMdd_hhmssms_[controller]_[method].json
this is what I have in my config-file:
<appender name="JsonFileAppender" type="log4net.Appender.RollingFileAppender" >
<file value="c:\temp\" />
<datePattern value="yyyyMMdd_hh.mm.ss.ms_%thread{CommonApplicationData}'.json'" />
<staticLogFileName value="false" />
<appendToFile value="true" />
<rollingStyle value="Composite" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="5MB" />
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%message%newline" />
</layout>
</appender>
This returns the following filename : 20160224_01.30.28.3028_P1rea24{Co30onApplicaPionDaPa}.json
one way is to set an Environment Variable in your code like:
Environment.SetEnvironmentVariable("APPENDER_FILE", "Your File Path");
and then, configure this environment variable in log4net XML:
<appender name="FileAppender" type="log4net.Appender.FileAppender">
<file value="${APPENDER_FILE}"/>
You can access the appenders of your log4net configuration at run-time like so
var repository = (Hierarchy)LogManager.GetRepository();
var appenders = repository.GetAppenders().Where(x => x is FileAppender);
You can get specific appender then by name
var appender = appenders.FirstOrDefault(x => x.Name.Equals("MyAppeader"));
Once you have an appender you can modify it how you like. You want to set the filepath
appender.File = #"c:\folder\yyyyMMdd_hhmssms_[controller]_[method].json";
You should not have the do anything else as log4net should automatically start using the new configuration.
Placing this all into a little helper method, you'd get this
public static void SetAppenderPath(string appender, string path)
{
var repository = (Hierarchy)LogManager.GetRepository();
var appenders = repository.GetAppenders().Where(x => x is FileAppender);
var appender = appenders.FirstOfDefault(x => x.Name.Equals(appender));
if (appender == null)
{
throw new ConfigurationErrorsException("Appender not found (" + appender + ")");
}
appender.File = path;
}
...
LogHelper.SetAppenderPath("MyAppender", #"yyyyMMdd_hhmssms_[controller]_[method].json");
I am using log4net together with ElasticSearch and Kibana.
By now my web.config looks like this:
<log4net>
<appender name="ElasticSearchAppender" type="log4net.ElasticSearch.ElasticSearchAppender, log4net.ElasticSearch">
<layout type="log4net.Layout.PatternLayout,log4net">
<param name="ConversionPattern" value="%date - %level - %message %property{location} %property{label} %property{mstimeload} %property{applicationid} %property{page}
%property{ipclient} %property{browser} %property{browsersignature} %property{appversion} %property{sessionuniquecodetag} %property{globalcountertailsloaded}
%property{ipserveraddress} %newline" />
</layout>
<connectionString value="Server=myip;Index=logstash;Port=9200;rolling=true"/>
<lossy value="true" />
<bufferSize value="100" />
<evaluator type="log4net.Core.LevelEvaluator">
<threshold value="ERROR"/>
</evaluator>
</appender>
<root>
<level value="ALL"/>
<appender-ref ref="ElasticSearchAppender" />
</root>
I have some custom parameters like location, label, mstimeload, applicationid, page, ipclient, ...
Everything works fine, but all of these parameters are of string type, instead I would like to have also integer or geo_point type, but I don't know how to tell log4net of which type is my parameter.
Then in c# I write my log like this:
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
log4net.ThreadContext.Properties["label"] = label;
log4net.ThreadContext.Properties["ipclient"] = ipaddress;
log4net.ThreadContext.Properties["browser"] = browserType;
log4net.ThreadContext.Properties["browsersignature"] = browserHashSignature;
log4net.ThreadContext.Properties["appversion"] = ASSettings.ApplicationVersion;
log4net.ThreadContext.Properties["mstimeload"] = msTime == null ? null : Convert.ToString(Convert.ToInt32(msTime.Value), CultureInfo.InvariantCulture);
log4net.ThreadContext.Properties["globalcountertailsloaded"] = globalCounter_tilesloaded == null ? null : Convert.ToString(globalCounter_tilesloaded.Value, CultureInfo.InvariantCulture);
log4net.ThreadContext.Properties["ipserveraddress"] = ipserveraddress;
log4net.ThreadContext.Properties["page"] = page;
log4net.ThreadContext.Properties["sessionuniquecodetag"] = sessionuniquecodetag;
log4net.ThreadContext.Properties["applicationid"] = applicationid;
log4net.ThreadContext.Properties["location"] = ASSecurity.GetLatLongFromIp(ipaddress);
log.Error(description, ex);
But I am not sure if this is the best way to do it or if there are also other ways.
I have been given a dll named MYLogger.dll which is apparently a wrapper around log4net and has a MyLogger and a DefaultLogger classes defined in it and both these classes inherit ILogger. And I have to log exceptions and info for an Asp.Net Web Api service which has several projects defined within one solution in .net.
And these the signature for MyLogger class
public MyLogger(string name, string configFilePath = "",
string newLogFileFolderName = "");
public MyLogger(Type t, string configFilePath = "",
string newLogFileFolderName = "");
public event EventHandler<EventArgs<string>> MessageLogged;
public void Log(LogLevel logLevel, string message, object[] args = null);
public void LogException(Exception ex, string customMessage = "",
LogLevel logLevel = LogLevel.Error);
And signature for DefaultLogger class is
public DefaultLog();
public static DefaultLog Logger { get; }
public event EventHandler<EventArgs<string>> MessageLogged;
public void Log(LogLevel logLevel, string message, object[] args = null);
public void LogException(Exception ex, string customMessage = "",
LogLevel logLevel = LogLevel.Error);
And my config file named MyLog.Config looks like
<configuration>
<!-- Register a section handler for the log4net section -->
<configSections>
<section name="log4net" type="System.Configuration.IgnoreSectionHandler" />
</configSections>
<log4net>
<appender name="ErrorFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="C\Data\Log\MyErrorLog.txt" />
<appendToFile value="true" />
<maxSizeRollBackups value="-1" />
<maximumFileSize value="10MB" />
<rollingStyle value="Size" />
<layout type="MyLogger.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%ndc] <%property{auth}> - %message%newline" />
</layout>
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<levelMin value="ERROR" />
<levelMax value="FATAL" />
</filter>
</appender>
<appender name="InfoFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="C\Data\Log\MyInfoLog.txt" />
<appendToFile value="true" />
<maxSizeRollBackups value="-1" />
<maximumFileSize value="10MB" />
<rollingStyle value="Size" />
<layout type="MyLogger.MyPatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%ndc] <%property{auth}> - %message%newline" />
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<levelMin value="INFO" />
<levelMax value="INFO" />
</filter>
</appender>
<root>
<level value="ALL" />
<appender-ref ref="ErrorFileAppender" />
<appender-ref ref="InfoFileAppender" />
</root>
</log4net>
</configuration>
And I'm trying to use both the logger class viz MyLogger for both exception logging and info logging as below.
private static ILogger log = new Logger(MethodBase.GetCurrentMethod()
.DeclaringType, #"~\MyLog.config"," ");
Even when i give path to second parameter(for either info or exception text file) rather being empty, still nothing is written to either of them. I tried to throw the exception but still no success for exception logging.
And with the help of log object I'm trying to achieve logging for info as below
string message = string.Format("The feature class name is {0} and the type is {1}",Name,Type);
//DefaultLog.Logger.Log(LogLevel.Info, message);
log.Log(LogLevel.Info, message);
as you can see I tried both with DefaultLog and log object(which is an implementation of ILog interface with MyLogger class) and the same way I'm trying to achieve exceptions using following code at the time some exception is thrown inside by a controller action
catch (HttpResponseException ex)
{
string errorMessage = string.Format("Getting {0} data gives error because either fcollection is empty or soemthing is null Error:{1}",
Name, ex.Message);
//DefaultLog.Logger.LogException(ex, errorMessage, LogLevel.Error);
log.LogException(ex, errorMessage, LogLevel.Error);
}
For both info and exception nothing gets logged/written into text files mentioned along with their respective paths inside my Xml config file.
And the weirdest thing about the two constructors of MyLogger class is that both constructors have string as a parameter for configfile path and the string as a parameter for newLogFileFolderName, how could I figure out that this newLogFileFolderName is asking for path for text file where info logs are written or text file where exception logs are written. And I'm assuming that inside the constructors of MyLogger class something like
XmlConfigurator.ConfigureAndWatch(new FileInfo(MyLog.config))
has been used that's why 1st parameter for config file has been substituted for ConfigureAndWatch ( ) method's argument but I have no idea what is the use of second parameter inside constructor code of MyLogger i.e do I need to instantiate MyLogger class twice once with path for info text file and second time path for exception text file as a second parameter in the constructor. That doesn't make sense to me.Its highly confusing. All suggestion will be highly appreciated.
This is my configuration for log4net:
<log4net>
<appender name="MyLogger" type="log4net.Appender.RollingFileAppender">
<file value="MyLog.log" />
<appendToFile value="true" />
<rollingStyle value="Size"/>
<maxSizeRollBackups value="20"/>
<maximumFileSize value="1000KB"/>
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss},%p,%m%n" />
</layout>
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="MyLogger" />
</root>
</log4net>
In C# I'm trying to get the name of the log file (which is MyLog.log). I googled and tried many things but failed to do so. Any help?
Thanks!
Solution is quite easy in your situation; just use this code:
var rootAppender = ((Hierarchy)LogManager.GetRepository())
.Root.Appenders.OfType<FileAppender>()
.FirstOrDefault();
string filename = rootAppender != null ? rootAppender.File : string.Empty;
When having multiple file appenders, you might want to get them by name. Also to make sure to get the appender even if it is not referenced by the root node, the following code helps:
public static string GetLogFileName(string name)
{
var rootAppender = LogManager.GetRepository()
.GetAppenders()
.OfType<FileAppender>()
.FirstOrDefault(fa => fa.Name == name);
return rootAppender != null ? rootAppender.File : string.Empty;
}
Since I already had a logger defined in the class I just used it. One thing to be aware of is that there may be more than one appender and often the first one is the console (which doesn't have a file). Here is my solution for what its worth.
using log4net;
using log4net.Appender;
using log4net.Repository;
namespace MyNameSpace {
public class MyClass {
private static readonly ILog logger = LogManager.GetLogger(typeof(MyClass));
public String GetLogFileName() {
String filename = null;
IAppender[] appenders = logger.Logger.Repository.GetAppenders();
// Check each appender this logger has
foreach (IAppender appender in appenders) {
Type t = appender.GetType();
// Get the file name from the first FileAppender found and return
if (t.Equals(typeof(FileAppender)) || t.Equals(typeof(RollingFileAppender))) {
filename = ((FileAppender)appender).File;
break;
}
}
return filename;
}
}
}
String filename = null;
Hierarchy hierarchy = LogManager.GetRepository() as Hierarchy;
Logger logger = hierarchy.Root;
IAppender[] appenders = logger.Repository.GetAppenders();
// Check each appender this logger has
foreach (IAppender appender in appenders)
{
Type t = appender.GetType();
// Get the file name from the first FileAppender found and return
if (t.Equals(typeof(FileAppender)) || t.Equals(typeof(RollingFileAppender)))
{
filename = ((FileAppender)appender).File;
break;
}
}
System.Diagnostics.Process.Start(filename); //for example, open file in notepad
((log4net.Appender.FileAppender)(_log.Logger.Repository.GetAppenders())[0]).File
If your config does not have a <root> node then the above solution will not work for you. Read on.
<log4net>
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="${LOCALAPPDATA}\Anonymous.log" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="2000KB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
</layout>
</appender>
<logger name="AnonymousLog">
<level value="All" />
<appender-ref ref="RollingFileAppender" />
</logger>
</log4net>
This retrieves the log file:
string path = (LogManager.GetCurrentLoggers()[0].Logger.Repository.GetAppenders()[0] as FileAppender).File;
The (hopefully) crash-proof version:
string path = null;
if (LogManager.GetCurrentLoggers().Length > 0 && LogManager.GetCurrentLoggers()[0].Logger.Repository.GetAppenders().Length > 0)
{
path = (LogManager.GetCurrentLoggers()[0].Logger.Repository.GetAppenders()[0] as FileAppender).File;
}
Finally, if you get stuck with log4net add this to your <appSettings> section:
<add key="log4net.Internal.Debug" value="true"/>
I didn't find the above code working.
This worked for me
var filename= ((log4net.Appender.FileAppender)(((log4net.Appender.IAppender[])((((((log4net.Repository.Hierarchy.Hierarchy)((((log4net.Core.LoggerWrapperImpl)(log)).Logger).Repository)).Root).Hierarchy.Root).Appenders).SyncRoot))[0])).File