ExamplesIn the interest of getting Log4Net up and running quickly, this part of the chapter is nothing but examples. To try to mix and match all of the types of .NET applications with all of the Appenders would be a nightmare. These examples are meant to complement the configuration information in Appendix D, "Log4Net Appender Configurations." Windows Forms and Console ApplicationsConsole Applications and Windows Forms use Log4Net in the exact same way. A .NET configuration file is needed, and with a few lines of code, Log4Net is up and running. The first example is a Windows Form (Listing 8.6 that features a FileAppender. Listing 8.14. Windows Form FileAppenderprivate void Form1_Load(object sender, System.EventArgs e) { try { manageClass = new ManagementClass("Win32_Processor"); manageCollection = manageClass.GetInstances(); foreach(ManagementObject mo in manageCollection) { foreach(PropertyData s in mo.Properties) { if(s.Name == "MaxClockSpeed") { log4net.MDC.Set("clock", mo[s.Name].ToString() + " MHz"); } } } manageClass = new ManagementClass("Win32_ComputerSystem"); manageCollection = manageClass.GetInstances(); foreach(ManagementObject mo in manageCollection) { foreach(PropertyData s in mo.Properties) { if(s.Name == "TotalPhysicalMemory") { log4net.MDC.Set("mem", mo[s.Name].ToString() + " bytes"); } } } } catch(Exception ex) { MessageBox.Show(ex.ToString()); } } Listing 8.10, the NDC example. This is a Console application that uses the EventLogAppender. Listing 8.15. Console Application NDC[STAThread] static void Main(string [] args) { try { using(log4net.NDC.Push(System.Environment.MachineName.ToString())) { using(log4net.NDC.Push(System.Environment.OSVersion.ToString())) { using(log4net.NDC.Push(System.Environment.Version.ToString())) { using(log4net.NDC.Push(System.Environment.UserName.ToString())) { if(_logger.IsDebugEnabled) { _logger.Debug("This is just a test of using NDC."); } } } } } } catch(Exception ex) { System.Diagnostics.Debug.WriteLine(ex.ToString()); Console.WriteLine(ex.ToString()); } } ClassLibraries.NET class libraries are compiled to dll files. Dlls cannot have their own config file but rather use the config file for the hosting application. Using .NET reflection, you can allow your class library to have a config file, but this is not recommended for two reasons. First, if the dll is going to reside in the GAC, it is very hard (and not recommended) to use a config file. Second, if several applications use your class library, changing the logging Level in the class library's config file will affect all applications using your class library, whereas keeping the Logger Level in the application will allow each application to use the class libraries logging at their own configurable Levels. ASP.NET and Web ServicesUsing Log4Net in an ASP.NET Web site or Web service is a great application of the logging framework. This is an ideal place to use the rolling file Appenders, as you may not have full permissions to the machine if you are using a hosting service.NOTEFor some Appenders like NTEventLog, you may need to perform a one-time elevation of privileges for the ASP.NET user.Listing 8.16 shows a simple Web service. Listing 8.16. A Simple Web Service Logging Routine[WebMethod] public void LogAMessage(string message, int level) { _logger = log4net.LogManager.GetLogger(typeof(LoggerService.Log)); switch(level) { case 1: _logger.Fatal(message); break; case 2: _logger.Error(message); break; case 3: _logger.Debug(message); break; case 4: _logger.Info(message); break; default: _logger.Debug(message); break; } } You still need to add the normal configuration information to the web.config file. The problem comes in getting the framework to configure (or reconfigure) each time the web.config file is altered. The normal trick of using [assembly:log4net.Config.DOMConfigurator(ConfigFile = "filename", ConfigFileExtension = "ext", Watch = "true")] will not work. This is because of the way the application is hosted by IIS. However, there is a very easy workaround. Whenever an ASP.NET application is restarted, including when web.config is changed, the application re-reads the Global.asax file. Therefore, you could place the code in Listing 8.17 into the global.asax.cs code file and reload the Log4NET configuration from the web.config file manually. When you change the web.config, this code will be rerun. Listing 8.17. Configuring Log4Net for ASP.NET and Web Servicesnamespace SomeNamespace { public class Global : System.Web.HttpApplication { protected void Application_Start(Object sender, EventArgs e) { log4net.Config.DOMConfigurator.Configure(); log4net.Info("Application Started"); } } } By using the code in Listing 8.17, you can configure Log4Net whenever the Webform or Web service is initialized. Serviced ComponentsLogging using Log4Net in a Serviced Component (COM+) application is just as easy as logging in a class library dll. The hard part comes when you try to get the configuration information to Log4Net. The recommended way around this is to configure Log4Net programmatically, as in Listing 8.18. Listing 8.18. ServicedComponent Programmatic Configuraiton//First configure programatically //Assume the config file will be named classlibrary1.dll.config //Could also hardcode this to a specified path. StringBuilder configpath = new StringBuilder(); configpath.AppendFormat("{0}.config", System.Reflection.Assembly.GetExecutingAssembly().Location); FileInfo configfile = new FileInfo(configpath.ToString()); log4net.Config.DOMConfigurator.ConfigureAndWatch(configfile); This allows the config file to be named [assemblyname].dll.config, and Log4Net will configure and watch for changes in the file, just like a normal configuration. RemotingLogging from your Remoting application is again similar to logging in any other class library dll. It would probably be best to use a database to log to since Remoting is sometimes distributed. Logging to the EventLog or to a file presupposes certain permissions on the machine. Using the SQL script and configuration from the ADONetAppender in Appendix E in conjunction with the PGAdmin II tool, we can create a PostgreSQL database for logging. This of course requires the use of Npgsql, which we will see in-depth in Chapter 10, "Database Development." Listing 8.19. Logging to PostgreSQL<appender name="ADONetAppender" type="log4net.Appender.ADONetAppender"> <param name="BufferSize" value="100" /> <param name="ConnectionType" value="Npgsql.NpgsqlConnection, Npgsql,Version=0.5.0.0, ![]() <param name="ConnectionString" value="data source=localhost;initial ![]() <param name="CommandText" value="INSERT INTO Log ([Date],[Thread],[Level],[Logger] ![]() ![]() <param name="Parameter"> <param name="ParameterName" value="@log_date" /> <param name="DbType" value="DateTime" /> <param name="Layout" type="log4net.Layout.RawTimeStampLayout" /> </param> <param name="Parameter"> <param name="ParameterName" value="@thread" /> <param name="DbType" value="String" /> <param name="Size" value="255" /> <param name="Layout" type="log4net.Layout.PatternLayout"> <param name="ConversionPattern" value="%t" /> </param> </param> <param name="Parameter"> <param name="ParameterName" value="@log_level" /> <param name="DbType" value="String" /> <param name="Size" value="50" /> <param name="Layout" type="log4net.Layout.PatternLayout"> <param name="ConversionPattern" value="%p" /> </param> </param> <param name="Parameter"> <param name="ParameterName" value="@logger" /> <param name="DbType" value="String" /> <param name="Size" value="255" /> <param name="Layout" type="log4net.Layout.PatternLayout"> <param name="ConversionPattern" value="%c" /> </param> </param> <param name="Parameter"> <param name="ParameterName" value="@message" /> <param name="DbType" value="String" /> <param name="Size" value="4000" /> <param name="Layout" type="log4net.Layout.PatternLayout"> <param name="ConversionPattern" value="%m" /> </param> </param> <param name="Parameter"> <param name="ParameterName" value="@exception" /> <param name="DbType" value="String" /> <param name="Size" value="2000" /> <param name="Layout" type="log4net.Layout.ExceptionLayout" /> </param> </appender> Appendix D. Windows ServicesWindows Services, as far as logging is concerned, are a lot like a Windows Form or Console Application executable. Many times distributed applications, especially when using Remoting, depend on a Windows Service to be running to host them. Many systems depend on services to be running, and there is no simple, nice way to automatically restart or check the health of a Windows Service as there is for a Web service. So, if that service goes down for whatever reason, this would definitely be a FATAL condition. Listing 8.20 shows a configuration that would be ideal for a service. This is a place where multiple Appenders would probably be needed, with this Appender handling the FATAL messages. Listing 8.20. Sending Only Fatal Messages via Immediate Email<appender name="EventLogAppender" type="log4net.Appender.EventLogAppender" > <layout type="log4net.Layout.PatternLayout"> <param name="ConversionPattern" value="%d [%t] %-5p %c [%x] - %m%n" /> </layout> </appender> <appender name="SMTPAppender" type="log4net.Appender.SMTPAppender"> <param name="To" value="me@myemail.com" /> <param name="From" value="MyService" /> <param name="Subject" value="Fatal Error Occured" /> <param name="SMTPHost" value="my.mailserver.com" /> <param name="LocationInfo" value="false" /> <param name="BufferSize" value="1" /> <param name="Lossy" value="false" /> <param name="Threshold" value="FATAL"/> <layout type="log4net.Layout.PatternLayout"> <param name="ConversionPattern" value="%n%d [%t]%-5p %c [%x] - %m%n%n%n" /> </layout> </appender> Listing 8.20's example shows that Log4Net is more than just a nice way to write out a log message. This example uses the Threshold of an SMTP Appender to send an email out on a FATAL log message. This email could be easily tied to a pager system for remote support. |