Showing posts with label log4net. Show all posts
Showing posts with label log4net. Show all posts

August 26, 2009

Log4net ADO.NET Appender

Here is a simple way to make sure you don't have to put the connectionstring in the config file for Log4Net and instead just pull it from the connectionString setting:
using System;
using System.Collections.Generic;
using System.Configuration;
using log4net.Appender;
using System.Data.Common;

namespace Log4net.Appender
{
public class AppSettingsConnectionStringAdoNetAppender : AdoNetAppender
{
string _connectionStringName;

public string ConnectionStringName
{
get { return _connectionStringName; }

set
{
if (string.IsNullOrEmpty(value))
throw new ArgumentException("Null or empty connection string name.");

try
{
ConnectionStringSettings connectionString =
ConfigurationManager.ConnectionStrings[value];

DbProviderFactory factory = DbProviderFactories.GetFactory(
connectionString.ProviderName);

using (DbConnection connection = factory.CreateConnection())
{
this.ConnectionType = connection.GetType().ToString();
this.ConnectionString = connectionString.ConnectionString;
}

_connectionStringName = value;
}
catch(Exception ex)
{
throw new ArgumentException("We can't initialize connection string from the name passed. " + value, ex);
}
}
}
}
}
Take this code and add it to your appender library or create your own library and build the assembly. After that, in your log4net config file you can call the appender now like any other appender:
<appender name="My_AdoNetAppender" type="Log4Net.Appender.AppSettingsConnectionStringAdoNetAppender, JLFramework.Log4Net.Appender">
</appender>

August 18, 2009

Audit using Log4Net

I had taken a web service off the hands of someone and it had no logging. I needed a quick way to log everything from every method in the code. I also needed to pull the user executing the method. In most cases this would be simple, but not in this webservice...I figured I would read it from a cookie that we had. Nothing would be easy as I knew I had to place statements in some methods, but I wanted to at least make a reusable class.

I used Log4Net and have the log spit out xml to make it easy to import or work with. The code is fairly simple to use:
//In the try
Auditor.Audit.Method(this.Context, "MethodName", new object[] { request });

//in the catch:
Auditor.Audit.Method(this.Context, "MethodName", new object[] { request }, ex);
The code that does the simple audit:
    public class Audit
{
private static AuditorCore m_core = new AuditorCore();
private static bool enabled = false;

static Audit()
{
log4net.Config.XmlConfigurator.Configure();

try
{
enabled = bool.Parse(ConfigurationSettings.AppSettings["Audit.Enabled"]);
}
catch(Exception)
{
enabled = false;
}
}

public static void Method(HttpContext context, string methodName, IEnumerable arguments, Exception exception)
{
if (enabled)
{
m_core.Method(context, methodName, arguments, exception);
}
}
public static void Method(HttpContext context, string methodName, IEnumerable arguments)
{
if (enabled)
{
m_core.Method(context, methodName, arguments);
}
}
}


The core class:

internal class AuditorCore
{
private log4net.ILog log = log4net.LogManager.GetLogger("Audit");

private Dictionary m_serializers =
new Dictionary();

public void Method(HttpContext context, string methodName, IEnumerable arguments)
{
Method(context, methodName, arguments, null);
}

public void Method(HttpContext context, string methodName, IEnumerable arguments, Exception exception)
{
lock (m_serializers)
{
log.Info(string.Format("",
methodName,
GetUserId(context)));

foreach (object argument in arguments)
{
string xmlText = SerializeToXmlString(argument);
log.Info(xmlText);
}

if (exception != null)
{
log.Error("");
}

log.Info("
");
}
}

private string SerializeToXmlString(object obj)
{
if(obj == null)
{
return "";
}

// Use below object to avoid namespaces in result xml.
XmlSerializerNamespaces xmlnsEmpty = new XmlSerializerNamespaces();
xmlnsEmpty.Add("", "");

XmlSerializer serializer = GetSerializer(obj.GetType());
using (StringWriter stringWriter = new StringWriter())
{
using (XmlWriter xmlWriter = XmlWriter.Create(stringWriter))
{
serializer.Serialize(xmlWriter, obj, xmlnsEmpty);
}

// Strip out the header.
string xmlText = stringWriter.ToString();
xmlText = xmlText.Substring(xmlText.IndexOf('>') + 1);

return xmlText;
}
}

private XmlSerializer GetSerializer(Type type)
{
if (!m_serializers.ContainsKey(type))
{
m_serializers[type] = new XmlSerializer(type);
}

return m_serializers[type];
}

private string GetUserId(HttpContext context)
{
if (context.Request.Cookies["MyCookie"] != null)
{
return context.Request.Cookies["MyCookie"]["userid"];
}
else
{
return null;
}
}
}

June 8, 2009

Log4Net and Powershell

Sure, why not! To be honest, I see no reason as we have other options in Powershell. Here is how you would do it:
Add-Type -Assembly System.Configuration
[System.Reflection.Assembly]::LoadFrom($MY_DIR + "\lib\log4net.dll")

#Reset
[log4net.LogManager]::ResetConfiguration()
#Configure
[log4net.Config.BasicConfigurator]::Configure()
$log = [log4net.LogManager]::getLogger("POShTest")

if($log.IsDebugEnabled)
{
$log.debug("Debug!")
}

$log.info("Info!")
$log.warn("Warn!")
$log.error("Error!")
$log.fatal("Fatal")