How to configure log4net with VSTO project in visual studio - c#

I was trying to build a simple outlook add in.
I created a VSTO project in Visual Studio 2017.
When the project is created by the Visual Studio, there is no app.config or web.config in the solution. I want to use log4net for this project. How should I configure it? I tried to add web.config or app.config for the project. But I was not able to get values from the configure file. I think the project cannot recognize them. I cannot use ConfigurationManager.AppSettings["key"] to get the value from the configure file.
Does anyone know how to use log4net in VSTO project?
Thank you.

Install Log4Net through the NuGet Package Manager. Then create a setting in the project properties, like asdf (you can delete the setting after you update the app.config file with the Log4Net sections), it will then create the app.config for you.
Here's the configuration in app.config for Log4Net I use on most of my projects. I created a new project with a setting asdf and added my standard Log4Net setup.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="ExcelAddIn1.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
</sectionGroup>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
</configSections>
<userSettings>
<ExcelAddIn1.Properties.Settings>
<setting name="asdf" serializeAs="String">
<value>asdf</value>
</setting>
</ExcelAddIn1.Properties.Settings>
</userSettings>
<log4net>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%ndc] - %message%newline"/>
</layout>
</appender>
<appender name="FileAppender" type="log4net.Appender.FileAppender">
<file value="C:\Temp\MyOfficeAddIn.log"/>
<appendToFile value="true"/>
<lockingModel type="log4net.Appender.FileAppender+MinimalLock"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date|%-5level|%message%newline"/>
</layout>
</appender>
<root>
<level value="ALL"/>
<appender-ref ref="FileAppender"/>
</root>
</log4net>
</configuration>
I usually create a class called ErrorHandler and add the following code.
using System;
using System.Linq;
using System.Text;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using Excel = Microsoft.Office.Interop.Excel;
using log4net;
using log4net.Config;
[assembly: log4net.Config.XmlConfigurator(Watch = true)]
Then I use the following methods to write to the log file
private static readonly ILog log = LogManager.GetLogger(typeof(ErrorHandler));
/// <summary>
/// Applies a new path for the log file by FileAppender name
/// </summary>
public static void SetLogPath()
{
XmlConfigurator.Configure();
log4net.Repository.Hierarchy.Hierarchy h = (log4net.Repository.Hierarchy.Hierarchy)LogManager.GetRepository();
string logFileName = System.IO.Path.Combine(Properties.Settings.Default.App_PathLocalData, AssemblyInfo.Product + ".log");
foreach (var a in h.Root.Appenders)
{
if (a is log4net.Appender.FileAppender)
{
if (a.Name.Equals("FileAppender"))
{
log4net.Appender.FileAppender fa = (log4net.Appender.FileAppender)a;
fa.File = logFileName;
fa.ActivateOptions();
}
}
}
}
/// <summary>
/// Create a log record to track which methods are being used.
/// </summary>
public static void CreateLogRecord()
{
try
{
// gather context
var sf = new System.Diagnostics.StackFrame(1);
var caller = sf.GetMethod();
var currentProcedure = caller.Name.Trim();
// handle log record
var logMessage = string.Concat(new Dictionary<string, string>
{
["PROCEDURE"] = currentProcedure,
["USER NAME"] = Environment.UserName,
["MACHINE NAME"] = Environment.MachineName
}.Select(x => $"[{x.Key}]=|{x.Value}|"));
log.Info(logMessage);
}
catch (Exception ex)
{
ErrorHandler.DisplayMessage(ex);
}
}
/// <summary>
/// Used to produce an error message and create a log record
/// <example>
/// <code lang="C#">
/// ErrorHandler.DisplayMessage(ex);
/// </code>
/// </example>
/// </summary>
/// <param name="ex">Represents errors that occur during application execution.</param>
/// <param name="isSilent">Used to show a message to the user and log an error record or just log a record.</param>
/// <remarks></remarks>
public static void DisplayMessage(Exception ex, Boolean isSilent = false)
{
// gather context
var sf = new System.Diagnostics.StackFrame(1);
var caller = sf.GetMethod();
var errorDescription = ex.ToString().Replace("\r\n", " "); // the carriage returns were messing up my log file
var currentProcedure = caller.Name.Trim();
var currentFileName = AssemblyInfo.GetCurrentFileName();
// handle log record
var logMessage = string.Concat(new Dictionary<string, string>
{
["PROCEDURE"] = currentProcedure,
["USER NAME"] = Environment.UserName,
["MACHINE NAME"] = Environment.MachineName,
["FILE NAME"] = currentFileName,
["DESCRIPTION"] = errorDescription,
}.Select(x => $"[{x.Key}]=|{x.Value}|"));
log.Error(logMessage);
// format message
var userMessage = new StringBuilder()
.AppendLine("Contact your system administrator. A record has been created in the log file.")
.AppendLine("Procedure: " + currentProcedure)
.AppendLine("Description: " + errorDescription)
.ToString();
// handle message
if (isSilent == false)
{
MessageBox.Show(userMessage, "Unexpected Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
I have a project in GitHub you can use as an example.

Related

log4net managedcoloredconsole not working with dynamic creation

I have a program that has a different set of modules called based an input parameter. Modules like Orders, Shipments, Pricing etc. I wrote a logging class with log4net being the foundation though there is a need for some custom logging as well. What I want is to have each module have its own logging file and to that point, I was able to get log4net to dynamically create the appenders for each file.
I was also able to get a console display for the times when it may be run manually, but what I lost (and cannot figure how to get it to work is the Colored Console appender. I found the basic solution here for creating appenders and I then used this link to figure out how to create console and ManagedColoredConsole appenders, but while it still writes to the console, I do not get color.
There is something missing, but I I don't know what. I wrote a small testing program to try and figure this out and this is the logging class:
using log4net;
using log4net.Appender;
using log4net.Layout;
using log4net.Repository.Hierarchy;
using System;
using System.Linq;
namespace TestLogging
{
public class Logging
{
// Since the current version of logging will require more custom fields passed into the logging table
// I'm going to set up a wrapper around the log for net processing. This should simplify the way we call it in
// the main program sections so we don't have to keep adding constants like pid and we can deal with variables
// like item, order number, shipping numbers
public static ILog log = null;
public string transType = "";
public string pid = "0";
private string logModule = "main";
private string path = "";
public Logging(string LogModule)
{
logModule = LogModule; // set up to default to main then pass in the specific log file name for log4net
SetLevel("Log4net.MainForm", "ALL");
path = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase);
string execPath = AppDomain.CurrentDomain.BaseDirectory;
if (log.Logger.Repository.GetAppenders().Count() == 0)
{
//CreateConsoleAppender();
CreateManagedColorConsoleAppender();
}
AddAppender(LogModule, CreateFileAppender(logModule, execPath + "\\logs\\" + logModule + ".log"));
}
public void Info(string message, string sohnum = null, string itmref = null, string sdhnum = null, double processtime = 0.0)
{
setCustom(sohnum, itmref, sdhnum, processtime);
log.Info(message);
}
private void setCustom(string sohnum = null, string itmref = null, string sdhnum = null, double processtime = 0.0)
{
log4net.ThreadContext.Properties["TransType"] = transType;
log4net.ThreadContext.Properties["sohnum_0"] = sohnum;
log4net.ThreadContext.Properties["itmref_0"] = itmref;
log4net.ThreadContext.Properties["sdhnum_0"] = sdhnum;
log4net.ThreadContext.Properties["processtime"] = processtime.ToString();
log4net.ThreadContext.Properties["pid"] = pid;
}
// Set the level for a named logger
public static void SetLevel(string loggerName, string levelName)
{
log = LogManager.GetLogger(loggerName);
Logger l = (Logger)log.Logger;
l.Level = l.Hierarchy.LevelMap[levelName];
}
// Add an appender to a logger
public static void AddAppender(string loggerName, IAppender appender)
{
log = LogManager.GetLogger(loggerName);
Logger l = (Logger)log.Logger;
l.Repository.Configured = true;
l.AddAppender(appender);
}
// Create a new file appender
public static IAppender CreateFileAppender(string name, string fileName)
{
FileAppender appender = new
FileAppender();
appender.Name = name;
appender.File = fileName;
appender.AppendToFile = true;
PatternLayout layout = new PatternLayout();
layout.ConversionPattern = "%d [%t] %-5p %c [%x] - %m%n";
layout.ActivateOptions();
appender.Layout = layout;
appender.ActivateOptions();
return appender;
}
public static IAppender CreateConsoleAppender()
{
ConsoleAppender appender = new ConsoleAppender();
appender.Name = "console";
PatternLayout layout = new PatternLayout();
layout.ConversionPattern = "%d [%t] %-5p %c [%x] - %m%n";
layout.ActivateOptions();
appender.Layout = layout;
appender.ActivateOptions();
var hierarchy = (Hierarchy)LogManager.GetRepository();
hierarchy.Configured = true;
hierarchy.Root.AddAppender(appender);
return appender;
}
public static IAppender CreateManagedColorConsoleAppender()
{
ManagedColoredConsoleAppender appender = new ManagedColoredConsoleAppender();
ManagedColoredConsoleAppender.LevelColors mapping = new ManagedColoredConsoleAppender.LevelColors();
appender.Name = "ManagedColoredConsoleAppender";
mapping.Level = log4net.Core.Level.Debug;
mapping.ForeColor = ConsoleColor.Blue;
appender.AddMapping(mapping);
mapping.Level = log4net.Core.Level.Info;
mapping.ForeColor = ConsoleColor.Green;
appender.AddMapping(mapping);
mapping.Level = log4net.Core.Level.Error;
mapping.ForeColor = ConsoleColor.Yellow;
appender.AddMapping(mapping);
mapping.Level = log4net.Core.Level.Fatal;
mapping.ForeColor = ConsoleColor.Red;
appender.AddMapping(mapping);
PatternLayout layout = new PatternLayout();
layout.ConversionPattern = "%d [%t] %-5p %c [%x] - %m%n";
layout.ActivateOptions();
appender.Layout = layout;
appender.ActivateOptions();
var hierarchy = (Hierarchy)LogManager.GetRepository();
hierarchy.Root.AddAppender(appender);
hierarchy.Configured = true;
hierarchy.Root.Level = log4net.Core.Level.Info;
return appender;
}
}
}
It is rough, but this is just for testing and learning.
This is the main program:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TestLogging
{
public class Program
{
//private Logging logging = new Logging("file");
private static Logging logit = new Logging("main");
static void Main(string[] args)
{
logit.Info("This is the main program");
ordersClass orders = new ordersClass();
orders.callMe();
shipments shipit = new shipments();
shipit.shipMe();
}
}
}
and one of the classes that writes to a different log file:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TestLogging
{
public class ordersClass
{
private Logging logit = new Logging("orders");
public void callMe()
{
logit.Info("Just placed an order");
}
}
}
When I set a break point to look at the log object I can see managed color is there as a root appender and the others added when first created. there is not a lot of info on using log4net programmatically, but I am hoping someone got this to work.
As I was reading more I discovered how to turn on internal logging for log4net. Put that in the app.config file and yes, it helps for it showed me how to fix my issue though why it does not work dynamically still alludes me.
<appSettings>
<add key="log4net.Internal.Debug" value="true"/>
</appSettings>
What I found was a few things:
Log4net does not need a config file to work if you are setting things up programmatically. Found that out because I had not set the 'copy to output directory' to other then 'do not copy' so no config file was being put in the the exe folder. This showed me you don't need a config file to do logging, but it still did not answer why no color.
If you decide to use a config file, but don't put in a appender that is referenced in the root, log4net logs the error, but keeps working. I had this
<appender-ref ref="ManagedColoredConsoleAppender" />
but no appender in the file. I added the ManagedColorConsole Appender and now I am getting both colored console messages AND logging into multiple files. This is a solution, but does not explain why I could add the color appender dynamically, but not have it work. If there is an answer please post. In the mean time this is a solved question.
<log4net>
<root>
<level value="ALL" />
<appender-ref ref="ManagedColoredConsoleAppender" />
</root>
<appender name="ManagedColoredConsoleAppender" type="log4net.Appender.ColoredConsoleAppender">
<mapping>
<level value="INFO" />
<foreColor value="Green, HighIntensity" />
</mapping>
<mapping>
<level value="DEBUG" />
<foreColor value="Green" />
</mapping>
<mapping>
<level value="ERROR" />
<foreColor value="Yellow, HighIntensity" />
</mapping>
<mapping>
<level value="FATAL" />
<foreColor value="Red, HighIntensity" />
</mapping>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
</layout>
</appender>
</log4net>

Unable to load shared library 'Kernel32.dll' or one of its dependencies. In order to help diagnose loading problems

Hello friends I have the following problem when trying to run my application in Linux Ubuntu x64, my application is written in Net Core C # with listening socket.
my code is net core 3.1:
using log4net;
using log4net.Config;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using Teltonika.Codec;
namespace UdpListener
{
class Program
{
private static readonly ILog Log = LogManager.GetLogger(typeof(Program));
static void Main()
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
XmlConfigurator.Configure();
IPAddress ip;
if (!IPAddress.TryParse(ConfigurationManager.AppSettings["ipAddress"], out ip))
{
Log.Error("Ip is not valid.");
throw new ArgumentException("Ip is not valid.");
}
int port;
if (!int.TryParse(ConfigurationManager.AppSettings["port"], out port))
{
Log.Error("Port is not valid.");
throw new ArgumentException("Port is not valid.");
}
Task.Run(async () =>
{
try
{
using (var udpClient = new UdpClient(new IPEndPoint(ip, port)))
{
Log.Info("Listening...");
while (true)
{
//IPEndPoint object will allow us to read datagrams sent from any source.
var receivedResults = await udpClient.ReceiveAsync();
byte[] data = receivedResults.Buffer;
Log.Info(string.Format("Received connection from: {0}", receivedResults.RemoteEndPoint));
Log.Info(string.Format("{0} - received [{1}]", DateTime.Now, String.Join("", data.Select(x => x.ToString("X2")).ToArray())));
var reader = new ReverseBinaryReader(new MemoryStream(data));
// Decode data
var avlData = new DataDecoder(reader).DecodeUdpData();
// Create response
var bytes = new List<byte>();
const short packetLength = 2 /* Id /+ 1 / Type / + 1 / Avl packet id /+ 1 / num of accepted elems */;
bytes.AddRange(BitConverter.GetBytes(BytesSwapper.Swap(packetLength)));
bytes.AddRange(BitConverter.GetBytes(BytesSwapper.Swap(avlData.PacketId)));
bytes.Add(avlData.PacketType);
bytes.Add(avlData.AvlPacketId);
bytes.Add((byte)avlData.AvlData.DataCount);
var response = bytes.ToArray();
Log.Info(string.Format("{0} - response [{1}]", DateTime.Now, String.Join("", bytes.Select(x => x.ToString("X2")).ToArray())));
await udpClient.SendAsync(response, response.Length, receivedResults.RemoteEndPoint);
}
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
});
Console.ReadLine();
}
}
}
my configurations setting app.config :
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
</configSections>
<appSettings>
<add key="ipAddress" value="198.199.67.142"/>
<add key="port" value="777"/>
<!--<add key="log4net.Internal.Debug" value="true"/>-->
</appSettings>
<log4net>
<appender name="Console" type="log4net.Appender.ColoredConsoleAppender" Target="Console.Error">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%logger - %message%newline"/>
</layout>
</appender>
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="log.txt"/>
<appendToFile value="true"/>
<rollingStyle value="Size"/>
<maxSizeRollBackups value="10"/>
<maximumFileSize value="500KB"/>
<staticLogFileName value="true"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%d %-5p %c %m%n"/>
</layout>
</appender>
<root>
<level value="INFO"/>
<appender-ref ref="Console"/>
<appender-ref ref="RollingFileAppender"/>
</root>
</log4net>
</configuration>
this is the error code i get, when I try to run it within linux ubuntu it returns this error:
log4net:ERROR Could not create Appender [Console] of type [log4net.Appender.ColoredConsoleAppender]. Reported error follows.
System.DllNotFoundException: Unable to load shared library 'Kernel32.dll' or one of its dependencies. In order to help diagnose loading problems, consider setting the LD_DEBUG environment variable: libKernel32.dll: cannot open shared object file: No such file or directory
at log4net.Appender.ColoredConsoleAppender.GetConsoleOutputCP()
at log4net.Appender.ColoredConsoleAppender.ActivateOptions()
at log4net.Repository.Hierarchy.XmlHierarchyConfigurator.ParseAppender(XmlElement appenderElement)
log4net:ERROR Appender named [Console] not found
Please Help.

Why is log4net not writing to a file?

I have added all parts of log4net, however it doesn't write to the file.
I'm working with the VS2012 LoadTest project.
Neither the System.Console.WriteLine or Debug.WriteLine() work, when running the LoadTest project.
I've added the assembly info line:
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "web.config", Watch = true)] //For log4net 1.2.10.0
I've:
- added webconfig section
- initialized an configured an XML initializer
- initialized new log4net with the proper log
My app.config:
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<log4net debug="true">
<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="Settings_CacheExplosion.txt" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="10MB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%-5p %d %5rms %-22.22c{1} %-18.18M - %m%n" />
</layout>
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="RollingLogFileAppender" />
</root>
</log4net>
</configuration>
My class:
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.17929
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace WebAndLoadTestProject1
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using log4net;
using log4net.Core;
using Microsoft.VisualStudio.TestTools.WebTesting;
public class Settings_CacheExplosion : WebTest
{
private static readonly ILog activityLog = LogManager.GetLogger("Activity");
private static int _ctidsCounter { get; set; }
public static int CtidsCounter
{
get
{
if (_ctidsCounter == 2000)
{
_ctidsCounter = 1000;
}
return _ctidsCounter++;
}
set
{
_ctidsCounter = value;
}
}
public Settings_CacheExplosion()
{
this.PreAuthenticate = true;
CtidsCounter = 1000;
log4net.Config.XmlConfigurator.Configure();
}
public override IEnumerator<WebTestRequest> GetRequestEnumerator()
{
WebTestRequest request1 = new WebTestRequest("http://clientservice.mam.qasite-services.com/settings");
request1.Method = "POST";
Debug.WriteLine(string.Format("ctid={0}", CtidsCounter));
request1.QueryStringParameters.Add("ctid", CtidsCounter.ToString(), false, false);
StringHttpBody request1Body = new StringHttpBody();
request1Body.ContentType = "";
request1Body.InsertByteOrderMark = false;
request1Body.BodyString = "";
request1.Body = request1Body;
activityLog.Debug(string.Format("ctid={0}", CtidsCounter));
//Console.WriteLine(string.Format("ctid={0}", CtidsCounter));
yield return request1;
request1 = null;
}
}
}
If you want log4net to read from the app.config, you have to add this to your AssemblyInfo.cs file:
[assembly: log4net.Config.XmlConfigurator(Watch = true)]
Looking at your app.config:
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
This works to ensure that the app will refuse to start on .NET 4.0 with an error on startup.
If you are using Framework .NET4.5, log4net does not support it. See frameworks section in http://logging.apache.org/log4net/release/features.html
use <param name = "Activity" value="Settings_CacheExplosion.txt" /> instead of <file value="Settings_CacheExplosion.txt" />. in your xml configuration section.

How can I programmatically update log4net configuration file?

I currently have the log4net config in the applications' app.config file, as such:
...
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
</configSections>
<log4net>
<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="logs\Service.log"/>
<appendToFile value="true"/>
<rollingStyle value="Date"/>
<datePattern value="yyyyMMdd"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline"/>
</layout>
</appender>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline"/>
</layout>
</appender>
<logger name="Data.WebService">
<level value="ALL"/>
<appender-ref ref="ConsoleAppender"/>
<appender-ref ref="RollingLogFileAppender"/>
</logger>
<logger name="Data.Host.HostService">
<level value="ALL"/>
<appender-ref ref="ConsoleAppender"/>
<appender-ref ref="RollingLogFileAppender"/>
</logger>
</log4net>
I know I can read this in via log4net.Config.XmlConfigurator.Configure();, however, I would like to be able to update it via some sort of call as well. I'll be accepting configuration from a web service and, once I've set the new config (currently only log level, but I'm not precluding other things being configurable down the road), I need to update what is in the config file.
Having all of the configs in one file is very convenient, however, I'm open to locating the config in another file if that makes it simpler.
Since there is no official method to do so, I wound up writing a method that uses xpath to locate the element(s) to change and then update accordingly. Works well enough for what I need to do and is more elegant than a brute-force "readinthefiletoastringthenreplacethetextthensavethestringtothefile" approach.
public enum Log4NetConfigItem
{
LOGLEVEL
}
public const string LOG4NET_CONFIGFILE = "log4net.config";
public void UpdateConfiguration(Log4NetConfigItem which, object value)
{
// Load the config file.
XmlDocument doc = new XmlDocument();
doc.Load(LOG4NET_CONFIGFILE);
// Create an XPath navigator for the document.
XPathNavigator nav = doc.CreateNavigator();
try
{
XPathExpression expr;
// Compile the correct XPath expression for the element we want to configure.
switch (which)
{
default:
case Log4NetConfigItem.LOGLEVEL:
// Compile a standard XPath expression
expr = nav.Compile("/configuration/log4net/logger/level");
break;
}
// Locate the node(s) defined by the XPath expression.
XPathNodeIterator iterator = nav.Select(expr);
// Iterate on the node set
while (iterator.MoveNext())
{
XPathNavigator nav2 = iterator.Current.Clone();
// Update the element as required.
switch (which)
{
default:
case Log4NetConfigItem.LOGLEVEL:
// Update the 'value' attribute for the log level.
SetAttribute(nav2, String.Empty, "value", nav.NamespaceURI, value.ToString());
break;
}
}
// Save the modified config file.
doc.Save(LOG4NET_CONFIGFILE);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
void SetAttribute(System.Xml.XPath.XPathNavigator navigator, String prefix, String localName, String namespaceURI, String value)
{
if (navigator.CanEdit == true)
{
// Check if given localName exist
if (navigator.MoveToAttribute(localName, namespaceURI))
{
// Exist, so set current attribute with new value.
navigator.SetValue(value);
// Move navigator back to beginning of node
navigator.MoveToParent();
}
else
{
// Does not exist, create the new attribute
navigator.CreateAttribute(prefix, localName, namespaceURI, value);
}
}
}
Note: The SetAttribute code I got from here.
This is basically this open issue for log4net - unfortunately it is not resolved yet.

Set log name in appender of log4net

I have class MyLogger, where I use log4net. How can I modify my appender to save log in specific logname (I want to set it by parameter logName).
public void AddEntry(string source, string logName, string contextInfo, string message, EventLogEntryType eventType)
{
log4net.ILog Log = log4net.LogManager.GetLogger(source);
Log.Error(String.Format("Context Info: {0}{1}{2}{3}", contextInfo, Environment.NewLine, Environment.NewLine, message));
}
<log4net>
<root>
<priority value="ALL" />
<appender-ref ref="EventLogAppender" />
</root>
This is myAppender. Now it writes in common logtype Application.
<appender name="EventLogAppender" type="log4net.Appender.EventLogAppender" >
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%logger (%property{myContext}) [%level]- %message%newline" />
</layout>
</appender>
</log4net>
I think what you are looking for is this:
<param name="LogName" value="MyLog" />
Some more information can be found here. If you do something like this you may want to have a look at this issue as well. Basically this is about registering your application so that the eventlog knows about it.
Edit (configuration by code):
Did not test it but that ought to do the trick:
foreach (AppenderSkeleton appender in this.Logger.Repository.GetAppenders())
{
var eventlogAppender = appender as EventLogAppender;
if (eventlogAppender != null)
{
eventlogAppender.LogName = "MyLog";
eventlogAppender.ActivateOptions();
break;
}
}
You could add some tests to verify that there is only one EventLogAppender, but probably you do not need to bother to do so.
this works:
<param name="LogName" type="log4net.Util.PatternString" value="%property{LogName}" />

Categories

Resources