File: Log4NetCapture.cs

package info (click to toggle)
mono 4.6.2.7+dfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 778,148 kB
  • ctags: 914,052
  • sloc: cs: 5,779,509; xml: 2,773,713; ansic: 432,645; sh: 14,749; makefile: 12,361; perl: 2,488; python: 1,434; cpp: 849; asm: 531; sql: 95; sed: 16; php: 1
file content (180 lines) | stat: -rw-r--r-- 4,737 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
// ****************************************************************
// 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
	}
}