• Download Enterprise library log file which is currently in use by asp.net

    I use Microsofts Enterprise Library in many web projects. The modules are very easy to use, so e.g. you have a log for your website up and running in minutes. The problem I faced: I write the log into textfiles, and of course they are always in use. I could download them via FTP and read offline, but what if I want to read it online? Of course I don’t have the files in the public webdirectory as it contains confidential information. So I need to provide a download mechanism, but there is one trap because the logfile is more or less always in use. So here is how to do it, and we also create a general procedure out of it so that the filename is retrieved from web.config instead of hardcoded.

    Add reference to Microsoft Enterprise Library

    Of course you need to add a reference to Microsoft.Practices.EnterpriseLibrary.Common and Microsoft.Practices.EnterpriseLibrary.Logging. Version number is not important as it should work fine with all releases.

    Update your web.config

    You need to configure your logging in web.config of course. You could manually modify web.config, or you use the included Enterprise Library Configuration application EntLibConfig.exe. You could find my example web.config at the bottom of this article. I’m using the Rolling Flat File Trace Listener and I’ve changed the logging so that only the local(!) time and the message is written. Of course in real projects you should use Log Categories, Title, severity, priority etc.

    Add logging to your .vb code

    First I always import the logging namespace into my vb.net code:

    Imports Microsoft.Practices.EnterpriseLibrary.Logging

    Now add some logging wherever you want.

    Add download button

    Add a new download button to your aspx page, e.g. like this:

    <asp:linkbutton id="GetLog" runat="server">Get Logfile</asp:linkbutton>

    IO.File.Open does not work because file is being used

    A typical approach to get access to the logfile would be something like this:

    Const Logfile As String = "C:\Temp\Rolling.log"
    Logger.Write("Get Logfile")
    Dim fs As System.IO.FileStream = System.IO.File.Open(Logfile, System.IO.FileMode.Open)

    But this does not work because the file is already in use by the logging process and so you will get the following error message:

    The process cannot access the file ‘C:\Temp\Rolling.log’ because it is being used by another process.

    Set correct access mode

    So the single important thing here is: You have to take care about the access mode! You only want to read the logfile, so inform the framework about it. And you also want to make sure that the logfile is still writeable during your read access, so add this to your command too. So using this command will avoid the problem:

    Dim fs As System.IO.FileStream = System.IO.File.Open(Logfile, System.IO.FileMode.Open,  IO.FileAccess.Read, IO.FileShare.ReadWrite)

    Get logfile filename from logging configuration of web.config

    With current version the filename is hardcoded in the download part. That’s not a good idea as the filename in the web.config might be changed, or it’s a different filename on your stage, live, beta and local version. So it would be better to retrieve it from your web.config so it’s always the correct file. In your download-button you only need to supply the name of the listener. This way it’s easy to have multiple download-buttons for multiple listeners. Here is how to retrieve the filename of the provided listener on the fly:

    Dim LoggingSection As Configuration.LoggingSettings =       
    Dim Listeners As Configuration.TraceListenerDataCollection = LoggingSection.TraceListeners
    Dim RequestedLogger As Configuration.RollingFlatFileTraceListenerData = DirectCast(Listeners.Get(listenerName),
    Dim Logfile As New IO.FileInfo(RequestedLogger.FileName)

    The source code

    Here is the source code of the vb.net file and web.config


    Private Sub GetLog_Click(sender As Object, e As System.EventArgs) Handles GetLog.Click
           ProvideLogfile("Rolling Flat File Trace Listener")
       End Sub
       Private Sub ProvideLogfile(listenerName As String)
           Logger.Write("Provide logfile for listener '" & listenerName & "'")
           Dim LoggingSection As Configuration.LoggingSettings = DirectCast(Web.Configuration.WebConfigurationManager.GetSection("loggingConfiguration"), Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.LoggingSettings)
           Dim Listeners As Configuration.TraceListenerDataCollection = LoggingSection.TraceListeners
           Dim RequestedLogger As Configuration.RollingFlatFileTraceListenerData = DirectCast(Listeners.Get(listenerName), Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.RollingFlatFileTraceListenerData)
           Dim Logfile As New IO.FileInfo(RequestedLogger.FileName)
           Logger.Write("File: '" & Logfile.FullName & "'")
           Dim fs As System.IO.FileStream = System.IO.File.Open(Logfile.FullName, System.IO.FileMode.Open, IO.FileAccess.Read, IO.FileShare.ReadWrite)
           Logger.Write("Filestream opened.")
           Dim btFile(fs.Length) As Byte
           fs.Read(btFile, 0, fs.Length)
           Logger.Write("Filestream read.")
           Logger.Write("Filestream closed.")
           Logger.Write("Creating Response")
           With Response
               .AddHeader("Content-disposition", "attachment;filename=" & Logfile.Name)
               .ContentType = "application/octet-stream"
           End With
           Logger.Write("Finished GetLog_Click")
       End Sub


    <?xml version="1.0"?>
            <section name="loggingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.LoggingSettings, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" />
        <loggingConfiguration name="" tracingEnabled="true" defaultCategory="General">
                <add name="Rolling Flat File Trace Listener" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.RollingFlatFileTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                    listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.RollingFlatFileTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                    fileName="C:\Temp\rolling.log" footer="" formatter="Text Formatter"
                    header="" rollInterval="Day" />
                <add type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                    template="{timestamp(local)}- {message}" name="Text Formatter" />
                <add switchValue="All" name="General">
                        <add name="Rolling Flat File Trace Listener" />
                <allEvents switchValue="All" name="All Events" />
                <notProcessed switchValue="All" name="Unprocessed Category" />
                <errors switchValue="All" name="Logging Errors & Warnings">
                        <add name="Rolling Flat File Trace Listener" />
            <compilation debug="true" strict="false" explicit="true" targetFramework="4.0" />

Leave a comment

If you want to share your opinion, leave a comment.

You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>