Click here to Skip to main content
15,886,733 members
Articles / Operating Systems / Windows

LOG4NET WebServiceAppender

Rate me:
Please Sign up or sign in to vote.
4.25/5 (9 votes)
27 Dec 2006CPOL3 min read 55.5K   1.1K   32  
Introducing a small appender that logs to a web service within the LOG4NET logging framework
namespace Zeta
{
	#region Using directives.
	// ----------------------------------------------------------------------

	using System;
	using System.Collections.Generic;
	using System.Text;
	using log4net.Core;
	using log4net.Appender;
	using log4net.Util;
	using ZetaLib.Core.Common;
	using System.ComponentModel;
	using log4net.Layout;
	using System.Net;
	using log4net.Filter;
	using System.Diagnostics;
	using ZetaLib.Core.Logging;

	// ----------------------------------------------------------------------
	#endregion

	/////////////////////////////////////////////////////////////////////////

	/// <summary>
	/// An appender for LOG4NET that is capable of appending to a web service.
	/// </summary>
	/// <remarks>
	/// See http://www.l4ndash.com/Log4NetMailArchive/tabid/70/forumid/1/tpage/1/view/topic/postid/17080/Default.aspx#17919
	///
	/// Available configuration options:
	/// 
	/// 	&lt;appender name="WebServiceAppender" type="Zeta.WebServiceAppender"&gt;
	/// 		&lt;!-- LOG4NET parameters. --&gt;
	/// 		&lt;filter type="log4net.Filter.LevelRangeFilter"&gt;
	/// 			&lt;param name="LevelMin" value="DEBUG"/&gt;
	/// 			&lt;param name="LevelMax" value="FATAL"/&gt;
	/// 		&lt;/filter&gt;
	/// 
	/// 		&lt;!-- General parameters. --&gt;
	/// 		&lt;param name="ApiKey" value="{0E12B21A-95B9-11DB-96C0-005056C00008}" /&gt;
	/// 
	/// 		&lt;!-- WebService parameters. --&gt;
	/// 		&lt;param name="Url" value="http://www.myserver.com/LoggingService.asmx" /&gt;
	/// 		&lt;param name="TimeoutSeconds" value="60" /&gt;
	/// 
	/// 		&lt;!-- Proxy parameters. --&gt;
	/// 		&lt;param name="UseProxy" value="false" /&gt;
	/// 		&lt;param name="ProxyUrl" value="http://myproxy:3128" /&gt;
	/// 		&lt;param name="ProxyBypassOnLocal" value="true" /&gt;
	/// 		&lt;param name="ProxyUseDefaultCredentials" value="true" /&gt;
	/// 		&lt;param name="ProxyCredentialsDomain" value="OFFICE" /&gt;
	/// 		&lt;param name="ProxyCredentialsUserName" value="MyUser" /&gt;
	/// 		&lt;param name="ProxyCredentialsPassword" value="MyPassword" /&gt;
	/// 	&lt;/appender&gt;
	/// </remarks>
	public class WebServiceAppender :
		AppenderSkeleton
	{
		#region Public properties, setable from the configuration file.
		// ------------------------------------------------------------------

		/// <summary>
		/// 
		/// </summary>
		public LevelRangeFilter Filter
		{
			get
			{
				return filter;
			}
			set
			{
				filter = value;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public string ApiKey
		{
			get
			{
				return apiKey;
			}
			set
			{
				apiKey = value;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public string Url
		{
			get
			{
				return url;
			}
			set
			{
				url = value;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public int TimeoutSeconds
		{
			get
			{
				return timeoutSeconds;
			}
			set
			{
				timeoutSeconds = value;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public bool UseProxy
		{
			get
			{
				return useProxy;
			}
			set
			{
				useProxy = value;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public string ProxyUrl
		{
			get
			{
				return proxyUrl;
			}
			set
			{
				proxyUrl = value;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public bool ProxyBypassOnLocal
		{
			get
			{
				return proxyBypassOnLocal.GetValueOrDefault( true );
			}
			set
			{
				proxyBypassOnLocal = value;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public bool ProxyUseDefaultCredentials
		{
			get
			{
				return proxyUseDefaultCredentials.GetValueOrDefault( true );
			}
			set
			{
				proxyUseDefaultCredentials = value;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public string ProxyCredentialsDomain
		{
			get
			{
				return proxyCredentialsDomain;
			}
			set
			{
				proxyCredentialsDomain = value;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public string ProxyCredentialsUserName
		{
			get
			{
				return proxyCredentialsUserName;
			}
			set
			{
				proxyCredentialsUserName = value;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public string ProxyCredentialsPassword
		{
			get
			{
				return proxyCredentialsPassword;
			}
			set
			{
				proxyCredentialsPassword = value;
			}
		}

		// ------------------------------------------------------------------
		#endregion

		#region Implementation of IOptionHandler.
		// ------------------------------------------------------------------

		/// <summary>
		/// 
		/// </summary>
		public override void ActivateOptions()
		{
			base.ActivateOptions();

			//Provide any checks based on Service config properties, if Service
			//config properties are valid initialize WebServiceAppender.

			InitializeServiceConnection();
		}


		// ------------------------------------------------------------------
		#endregion

		#region Override implementation of AppenderSkeleton.
		// ------------------------------------------------------------------

		/// <summary>
		/// 
		/// </summary>
		protected override void Append(
			LoggingEvent loggingEvent )
		{
			try
			{
				// Call the web service, but only if filtered correctly.
				if ( filter == null ||
					(loggingEvent.Level >= filter.LevelMin &&
					loggingEvent.Level <= filter.LevelMax) )
				{
					string message = loggingEvent.RenderedMessage;

					if ( !string.IsNullOrEmpty( message ) )
					{
						message = message.Trim();
					}

					Logging.WebServiceCommunicationInformation info =
						new Zeta.Logging.WebServiceCommunicationInformation();

					info.ApiKey = apiKey;
					info.ExceptionSerializedAsString =
						StringHelper.SerializeToString(
						loggingEvent.ExceptionObject );
					info.Level = loggingEvent.Level.Name;
					info.Message = message;

					// Provide additional context information.
					info.ContextInformation = 
						ZetaLib.Core.Logging.LoggingInformation.All;

					// Call the web service.
					_serviceLogging.LogAsync(
						info,
						Guid.NewGuid() );
				}
			}
			catch ( Exception exc )
			{
				ErrorHandler.Error(
					"Unable to send loggingEvent to Logging Service",
					exc,
					ErrorCode.WriteFailure );
			}
		}

		/// <summary>
		/// 
		/// </summary>
		protected override bool RequiresLayout
		{
			get
			{
				return false;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		protected override void OnClose()
		{
			base.OnClose();

			//Release any resource that were needed.
			if ( _serviceLogging != null )
			{
				_serviceLogging.Dispose();
				_serviceLogging = null;
			}
		}

		// ------------------------------------------------------------------
		#endregion

		#region Private methods.
		// ------------------------------------------------------------------

		/// <summary>
		/// 
		/// </summary>
		private void InitializeServiceConnection()
		{
			try
			{
				//Code any Service initialization needed for WebServiceAppender to work.
				//This is called from ActiveOptions.
				//Instantiate the WebService.
				if ( _serviceLogging == null )
				{
					_serviceLogging = new Zeta.Logging.LoggingService();

					_serviceLogging.LogCompleted +=
						new Zeta.Logging.LogCompletedEventHandler(
						_serviceLogging_LogCompleted );

					// --

					if ( !string.IsNullOrEmpty( url ) )
					{
						_serviceLogging.Url = url;
					}

					if ( timeoutSeconds > 0 )
					{
						_serviceLogging.Timeout = timeoutSeconds * 1000;
					}

					if ( useProxy )
					{
						WebProxy proxy = new WebProxy();

						proxy.Address = new Uri( proxyUrl );

						proxy.BypassProxyOnLocal =
							proxyBypassOnLocal.GetValueOrDefault(
							proxy.BypassProxyOnLocal );
						proxy.UseDefaultCredentials =
							proxyUseDefaultCredentials.GetValueOrDefault(
							proxy.UseDefaultCredentials );

						if ( !proxy.UseDefaultCredentials )
						{
							NetworkCredential credentials =
								new NetworkCredential();

							credentials.Domain = proxyCredentialsDomain;
							credentials.UserName = proxyCredentialsUserName;
							credentials.Password = proxyCredentialsPassword;

							proxy.Credentials = credentials;
						}

						_serviceLogging.Proxy = proxy;
					}
				}
			}
			catch ( Exception exc )
			{
				// TODO: Add Service name to error message.
				ErrorHandler.Error(
					"Could not initialize the service",
					exc,
					ErrorCode.GenericFailure );

				// TODO: Reset the Service object to a known state if needed.
			}
		}

		/// <summary>
		/// Event handler.
		/// </summary>
		private void _serviceLogging_LogCompleted(
			object sender,
			AsyncCompletedEventArgs e )
		{
			if ( e.Error != null )
			{
				ErrorHandler.Error(
					"Unable to send loggingEvent to Logging Service",
					e.Error,
					ErrorCode.WriteFailure );
			}
		}

		// ------------------------------------------------------------------
		#endregion

		#region Private variables.
		// ------------------------------------------------------------------

		private string apiKey;
		private string url;
		private int timeoutSeconds;
		private bool useProxy = false;

		private string proxyUrl;
		private bool? proxyBypassOnLocal;
		private bool? proxyUseDefaultCredentials;
		private string proxyCredentialsDomain;
		private string proxyCredentialsUserName;
		private string proxyCredentialsPassword;

		private Logging.LoggingService _serviceLogging = null;

		private LevelRangeFilter filter;

		// ------------------------------------------------------------------
		#endregion
	}

	/////////////////////////////////////////////////////////////////////////
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Chief Technology Officer Zeta Software GmbH
Germany Germany
Uwe does programming since 1989 with experiences in Assembler, C++, MFC and lots of web- and database stuff and now uses ASP.NET and C# extensively, too. He has also teached programming to students at the local university.

➡️ Give me a tip 🙂

In his free time, he does climbing, running and mountain biking. In 2012 he became a father of a cute boy and in 2014 of an awesome girl.

Some cool, free software from us:

Windows 10 Ereignisanzeige  
German Developer Community  
Free Test Management Software - Intuitive, competitive, Test Plans.  
Homepage erstellen - Intuitive, very easy to use.  
Offline-Homepage-Baukasten

Comments and Discussions