Log4Net

Oct 25, 2011 at 5:54 PM

Hello, I am testing the solution but Log4Net is not logging errors in the database. Can you help me please?

Oct 28, 2011 at 10:29 PM

I too was having problems getting the Log4Net logging to go into the database.

It turns out, the database table called "Log" was not created when the initial MyFinance table was created.

You can go to this page: http://logging.apache.org/log4net/release/config-examples.html.

On that page, use the SQL script to create the Log table:

CREATE TABLE [dbo].[Log] (   

[Id] [int] IDENTITY (1, 1) NOT NULL,   

[Date] [datetime] NOT NULL,   

[Thread] [varchar] (255) NOT NULL,   

[Level] [varchar] (50) NOT NULL,   

[Logger] [varchar] (255) NOT NULL,   

[Message] [varchar] (4000) NOT NULL,   

[Exception] [varchar] (2000) NULL)

 

And then modify the web.config file for the <log4net> element to add the extra parameter for the exception item. The Apache link I supplied above shows what you need to change to match.

Once you set these up, the logging works great! I have confirmed it.

Regards,

Andre

Oct 29, 2011 at 12:06 AM

I did it, but still doesn't work. This is my web.config:

<?xml version="1.0" encoding="utf-8"?>
<!--
  For more information on how to configure your ASP.NET application, please visit
  http://go.microsoft.com/fwlink/?LinkId=152368
  -->
<configuration>
  <configSections>
    <sectionGroup name="fiftyOne">
      <section name="log" type="FiftyOne.Foundation.Mobile.Configuration.LogSection, FiftyOne.Foundation" requirePermission="false" allowDefinition="Everywhere" restartOnExternalChanges="false" allowExeDefinition="MachineToApplication" />
      <section name="redirect" type="FiftyOne.Foundation.Mobile.Configuration.RedirectSection, FiftyOne.Foundation" requirePermission="false" allowDefinition="Everywhere" restartOnExternalChanges="false" allowExeDefinition="MachineToApplication" />
      <section name="wurfl" type="FiftyOne.Foundation.Mobile.Detection.Wurfl.Configuration.WurflSection, FiftyOne.Foundation" requirePermission="false" allowDefinition="Everywhere" restartOnExternalChanges="false" allowExeDefinition="MachineToApplication" />     
    </sectionGroup>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,Log4net"/>
  </configSections>
  <connectionStrings>
    <add name="MyFinanceContext" connectionString="data source=.\SQLEXPRESS;Database=MyFinance;Trusted_Connection=true;" providerName="System.Data.SqlClient" />
    <add name="ApplicationServices" connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true" providerName="System.Data.SqlClient" />
    <add name="TableAuthDB" providerName="System.Data.SqlClient" connectionString="Data Source=.\SQLExpress;Integrated Security=True;User Instance=True;AttachDBFilename=|DataDirectory|TableAuthDB.mdf" />
  </connectionStrings>
  <appSettings>
    <add key="ClientValidationEnabled" value="true" />
    <add key="UnobtrusiveJavaScriptEnabled" value="true" />
    <!-- Inicio. Para que funcione con MVC 4 preview -->
    <!--<add key="webpages:Version" value="1.0.0.0"/> 
    <add key="ClientValidationEnabled" value="true"/> 
    <add key="UnobtrusiveJavaScriptEnabled" value="true"/>-->
    <!-- Fin. Para que funcione con MVC 4 preview -->    
  </appSettings>
  <system.web>
    <customErrors mode="On"> </customErrors>
    <compilation debug="true" targetFramework="4.0">
      <assemblies>
        <add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.Web.Helpers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
      </assemblies>
    </compilation>
    <authentication mode="Forms">
      <forms loginUrl="~/Account/LogOn" timeout="2880" />
    </authentication>
    <membership defaultProvider="TableMembershipProvider">
      <providers>
        <clear />
        <add name="TableMembershipProvider" type="Altairis.Web.Security.TableMembershipProvider, Altairis.Web.Security" connectionStringName="MyFinanceContext" minRequiredPasswordLength="6" minRequiredNonAlphanumericCharacters="0" passwordStrengthRegularExpression="" applicationName="MyFinance" />
      </providers>
    </membership>
    <roleManager enabled="true" defaultProvider="TableRowProvider">
      <providers>
        <clear />
        <add name="TableRowProvider" type="Altairis.Web.Security.TableRoleProvider, Altairis.Web.Security" connectionStringName="MyFinanceContext" />
      </providers>
    </roleManager>
    <!--<membership defaultProvider="TableMembershipProvider">
      <providers>
        <clear />
        <add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="ApplicationServices" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="/" />
        <add name="TableMembershipProvider" type="Altairis.Web.Security.TableMembershipProvider, Altairis.Web.Security" connectionStringName="MyFinanceContext" />
      </providers>
    </membership>
    <profile>
      <providers>
        <clear />
        <add name="AspNetSqlProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="ApplicationServices" applicationName="/" />
      </providers>
    </profile>
    <roleManager enabled="false">
      <providers>
        <clear />
        <add name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="ApplicationServices" applicationName="/" />
        <add name="AspNetWindowsTokenRoleProvider" type="System.Web.Security.WindowsTokenRoleProvider" applicationName="/" />
      </providers>
    </roleManager>-->
    <pages>
      <namespaces>
        <add namespace="System.Web.Helpers" />
        <add namespace="System.Web.Mvc" />
        <add namespace="System.Web.Mvc.Ajax" />
        <add namespace="System.Web.Mvc.Html" />
        <add namespace="System.Web.Routing" />
        <add namespace="System.Web.WebPages" />
        <add namespace="MvcPaging" />
      </namespaces>
    </pages>
    <httpModules>
      <!-- IIS 6.0 & Visual Studio - Registers a module that is used to redirect new requests to the web site.-->
      <!--<add name="Mobile Redirect" type="FiftyOne.Foundation.Mobile.Redirection.RedirectModule, FiftyOne.Foundation"/>-->
    </httpModules>
  </system.web>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true">
      <add name="Mobile Redirect" type="FiftyOne.Foundation.Mobile.Redirection.RedirectModule, FiftyOne.Foundation" />
    </modules>
  </system.webServer>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="3.0.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
  <fiftyOne>
    <!--<redirect> element controls how requests from mobile devices are handled.
    mobileHomePageUrl   Previously mobileRedirectUrl under the mobile/toolkit element.
                        A url to direct mobile devices to instead of the normal web sites 
                        landing page. (Optional)
    firstRequestOnly    If set to true only the first request received by the web site is
                        redirected to the mobileUrl when the site is accessed from a mobile
                        device. (Optional � defaults to true)
    timeout             The number of minutes of inactivity that should occur before the 
                        requesting device should be treated as making a new request to the
                        web site for the purposes of redirection. If the session is available
                        the session timeout will be used and override this value. (Optional
                        -defaults to 20 minutes)
    devicesFile	        A file used to store the details of devices that have previously
                        accessed the web site to determine if they're making a subsequent
                        request. Needed to ensure multiple worker processes have a consistent
                        view of previous activity. (Optional � random behaviour will be 
                        experienced if not specified on web sites with more than one worker
                        processes)
    mobilePagesRegex    A regular expression that when applied to the current request Path
                        (context.Request.AppRelativeCurrentExecutionFilePath) or the requesting 
                        Urlwill return true if it should be considered a mobile page. Use 
                        this attribute to tell redirection about mobile pages derived from base
                        classes such as System.Web.UI.Page. Redirection needs to be aware of
                        mobile pages so that requests to these pages can be ignored. Any page
                        that derives from System.Web.UI.MobileControls.MobilePage will 
                        automatically be treated as a mobile page irrespective of this 
                        attribute. (Optional)
    originalUrlAsQueryString
                        If set to true the redirected URL will have the original requesting Url 
                        encoded and included as the origUrl query string parameter in the 
                        redirected Url. This will enable the mobile home page to determine the 
                        original requested resource providing the option to display a mobile
                        friendly version. (Optional � defaults to false)
    locations/location  Provides details of different locations requests can be directed to based
                        on the values of defined properties associated with the device or request.
                        (Optional)
      name              A unique identifier for the location. Used for debugging in the log file.(Mandatory)                  
      url               the URL of the redirect location to use if all the properties in the 
                        collection match. (Mandatory)
      matchExpression   can be used to provide a regular expression which will take the requesting
                        URL as input match segments to be used in place of numeric parameters contained
                        within {} in the url attribute. (Optional)                       
                        The location element contains a collection of criteria that all need to match 
                        for the location to be used. Two attributes must be specified with each entry.
      property          the property of HttpRequest, HttpRequest.Browser or WURFL capability to 
                        use when evaluating the matchExpression attribute. (Mandatory)
      matchExpression   a regular expression used to evaluate the value of the property. (Mandatory)                        
                        -->
    <redirect mobileHomePageUrl="~/Mobile/Home" firstRequestOnly="false" devicesFile="~/App_Data/Devices.dat" timeout="20" mobilePagesRegex="/Mobile/" />
    <!--<log> element controls where and how much information should be recorded in the log.    
    logFile   The location of the log file. (Mandatory)
    logLevel  Values include Debug|Info|Warn|Fatal and control the level of information
              logged. Detauls to Fatal if not specified. (Optional)-->
    <log logFile="~/App_Data/Log.txt" logLevel="Info" />
    <!--<wurfl> element controls device data and new device handling.
    wurflFilePath         is the path of the main wurfl file (mandatory).
    wurflPatches          defines where any additional patch files can be located (optional).
    newDevicesURL         provides a URL where new devices found on your server can be recorded
                          (optional).
    newDeviceDetail       can be "minimum" or "maximum" and controls the HTTP header 
                          information sent to location defined in newDevicesUrl (optional).
    useActualDeviceRoot   When set to true only Wurfl devices marked with the attribute "actual_device_root"
                          are used to provide capabilities. Child devices will continue to be used to 
                          for device matching but their capabilities will not be used. This is an advanced
                          feature for those familar with WURFL. (optional)  
    capabilitiesWhiteList Using the capabilityName attribute of the add elements lists the Wurfl capabilities
                          required by the mobile web application. Providing this list prevents the entire list
                          of capabilities from being loaded slightly improving performance.-->
    <wurfl wurflFilePath="~/App_Data/wurfl.xml.gz" newDeviceDetail="maximum" newDevicesURL="http://devices.51degrees.mobi/new.ashx" useActualDeviceRoot="false">
      <wurflPatches>
        <add name="browser_definitions" filePath="~/App_Data/web_browsers_patch.xml" enabled="true" />
      </wurflPatches>
    </wurfl>
  </fiftyOne>
  <!--<log4net>
    <appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
      <file value="C:\Temp\log4net.log" />
      <appendToFile value="true" />
      <maximumFileSize value="500KB" />
      <maxSizeRollBackups value="2" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date %level %logger - %message%newline" />
      </layout>
    </appender>
    <root>
      <level value="All" />
      <appender-ref ref="RollingFile" />
    </root>
  </log4net>-->
  <log4net>
    <root>
      <level value="ALL"/>
      <appender-ref ref="ADONetAppender"/>
    </root>
    <appender name="ADONetAppender" type="log4net.Appender.AdoNetAppender">
      <bufferSize value="1" />
      <connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
      <connectionString value="data source=.\SQLEXPRESS;Database=MyFinance;Trusted_Connection=true;" />
      <commandText value="INSERT INTO Log ([Date],[Thread],[Level],[Logger],[Message],[Exception]) VALUES (@log_date, @thread, @log_level, @logger, @message, @exception)" />
      <parameter>
        <parameterName value="@log_date" />
        <dbType value="DateTime" />
        <layout type="log4net.Layout.RawTimeStampLayout" />
      </parameter>
      <parameter>
        <parameterName value="@thread" />
        <dbType value="String" />
        <size value="255" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%thread" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value="@log_level" />
        <dbType value="String" />
        <size value="50" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%level" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value="@logger" />
        <dbType value="String" />
        <size value="255" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%logger" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value="@message" />
        <dbType value="String" />
        <size value="4000" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%message" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value="@exception" />
        <dbType value="String" />
        <size value="2000" />
        <layout type="log4net.Layout.ExceptionLayout" />
      </parameter>
    </appender>
  </log4net>
</configuration>

Oct 31, 2011 at 3:49 PM
Edited Oct 31, 2011 at 3:50 PM

Hi japonte,

Well, there's one more piece to the puzzle. It turns out, the original project doesn't actually have any logging turned on.

So, to test it out, I updated the HomeController.cs to add the special logging attribute called UserTrackerLogAttribute.

To see how I used it, here's my updated HomeController.cs with the UserTrackerLogAttribute added to the default Index action:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MyFinance.Service;
using System.Web.Helpers;
using System.Globalization;
using MyFinance.Data;
using MyFinance.Data.Infrastructure;
using MyFinance.Web.Helpers;
 
namespace MyFinance.Web.Controllers
{
    public class HomeController : Controller
    {
 
       
        public ActionResult Chart()
        {           
            return null;
         }
        [UserTrackerLog]
        public ActionResult Index()
        {
            
            return View();
        }
 
        public ActionResult About()
        {
            return View();
        }        
    }   
}

 

If you add that attribute and then run the app (assuming your web.config is all updated and you have the Log table created properly

in your SQL Express system), you should get a log entry generated each time you load the Index page.

Andre

Oct 31, 2011 at 4:43 PM

Thanks, It works, but the field Log.Exception doesn't store exception details.

Oct 31, 2011 at 5:29 PM

Hi japonte,

That's because the [UserTrackerLog] attribute calls the LoggingService.Log(string) method so it doesn't pass an exception object to be recorded.

Log4Net has a lot of power and capabilities so if you want to log exceptions in your own code, you would have to write some of your own logging code.

Get a reference to the Log4Net object (see the LoggingService.cs class to see how they do it), and then call the logger with whatever level of logging

you'd like (Debug, Error, Fatal, Info, Warn) and pass the Exception type object to the logger when you're inside your catch{} clause.

None of this code is written in the sample application provided. This sample only shows a few basic techniques, the rest you have to write yourself.

 

Cheers,

Andre

Nov 1, 2011 at 3:20 AM

Thank you very much, Oakmario.