Jo Shields a575963da9 Imported Upstream version 3.6.0
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
2014-08-13 10:39:27 +01:00

181 lines
4.8 KiB
C#

// ****************************************************************
// Copyright 2008, Charlie Poole
// This is free software licensed under the NUnit license. You may
// obtain a copy of the license at http://nunit.org/?p=license&r=2.4
// ****************************************************************
using System;
using System.IO;
using System.Reflection;
using BF = System.Reflection.BindingFlags;
namespace NUnit.Core
{
/// <summary>
/// Proxy class for operations on a real log4net appender,
/// allowing NUnit to work with multiple versions of log4net
/// and to fail gracefully if no log4net assembly is present.
/// </summary>
public class Log4NetCapture : LogCapture
{
private Assembly log4netAssembly;
private Type appenderType;
private Type basicConfiguratorType;
private object appender;
private bool isInitialized;
// Layout codes that work for versions from
// log4net 1.2.0.30714 to 1.2.10:
//
// %a = domain friendly name
// %c = logger name (%c{1} = last component )
// %d = date and time
// %d{ABSOLUTE} = time only
// %l = source location of the error
// %m = message
// %n = newline
// %p = level
// %r = elapsed milliseconds since program start
// %t = thread
// %x = nested diagnostic content (NDC)
private static readonly string logFormat =
"%d{ABSOLUTE} %-5p [%4t] %c{1} [%x]- %m%n";
protected override void StartCapture()
{
if ( IsInitialized )
{
string threshold = DefaultThreshold;
if ( !SetLoggingThreshold( threshold ) )
SetLoggingThreshold( "Error" );
SetAppenderTextWriter( this.Writer );
ConfigureAppender();
}
}
protected override void StopCapture()
{
if ( appender != null )
{
SetLoggingThreshold( "Off" );
SetAppenderTextWriter( null );
}
}
#region Helpers
private bool IsInitialized
{
get
{
if ( isInitialized )
return true;
try
{
log4netAssembly = Assembly.Load( "log4net" );
if ( log4netAssembly == null ) return false;
appenderType = log4netAssembly.GetType(
"log4net.Appender.TextWriterAppender", false, false );
if ( appenderType == null ) return false;
basicConfiguratorType = log4netAssembly.GetType(
"log4net.Config.BasicConfigurator", false, false );
if ( basicConfiguratorType == null ) return false;
appender = TryCreateAppender();
if ( appender == null ) return false;
SetAppenderLogFormat( logFormat );
isInitialized = true;
}
catch
{
}
return isInitialized;
}
}
private Assembly TryLoadLog4NetAssembly()
{
Assembly assembly = null;
try
{
assembly = Assembly.Load( "log4net" );
}
catch
{
return null;
}
return assembly;
}
/// <summary>
/// Attempt to create a TextWriterAppender using reflection,
/// failing silently if it is not possible.
/// </summary>
private object TryCreateAppender()
{
ConstructorInfo ctor = appenderType.GetConstructor( Type.EmptyTypes );
object appender = ctor.Invoke( new object[0] );
return appender;
}
private void SetAppenderLogFormat( string logFormat )
{
Type patternLayoutType = log4netAssembly.GetType(
"log4net.Layout.PatternLayout", false, false );
if ( patternLayoutType == null ) return;
ConstructorInfo ctor = patternLayoutType.GetConstructor( new Type[] { typeof(string) } );
if ( ctor != null )
{
object patternLayout = ctor.Invoke( new object[] { logFormat } );
if ( patternLayout != null )
{
PropertyInfo prop = appenderType.GetProperty( "Layout", BF.Public | BF.Instance | BF.SetProperty );
if ( prop != null )
prop.SetValue( appender, patternLayout, null );
}
}
}
private bool SetLoggingThreshold( string threshold )
{
PropertyInfo prop = appenderType.GetProperty( "Threshold", BF.Public | BF.Instance | BF.SetProperty );
if ( prop == null ) return false;
Type levelType = prop.PropertyType;
FieldInfo levelField = levelType.GetField( threshold, BF.Public | BF.Static | BF.IgnoreCase );
if ( levelField == null ) return false;
object level = levelField.GetValue( null );
prop.SetValue( appender, level, null );
return true;
}
private void SetAppenderTextWriter( TextWriter writer )
{
PropertyInfo prop = appenderType.GetProperty( "Writer", BF.Instance | BF.Public | BF.SetProperty );
if ( prop != null )
prop.SetValue( appender, writer, null );
}
private void ConfigureAppender()
{
MethodInfo configureMethod = basicConfiguratorType.GetMethod( "Configure", new Type[] { appenderType } );
if ( configureMethod != null )
configureMethod.Invoke( null, new object[] { appender } );
}
#endregion
}
}