Click here to Skip to main content
14,768,449 members
Articles » General Programming » Programming Tips » General
Posted 20 Feb 2021


9 bookmarked

Simple Log Viewer

Rate me:
Please Sign up or sign in to vote.
5.00/5 (4 votes)
21 Feb 2021MIT
Show Simple Log - see the article by Jochen Scharr - in the browser with a nice layout
Simple Log by Jochen Scharr writes log items in XML format. This small extension adds an embedded XSLT stylesheet to the XML. While still unchanged and valid XML browsers pick up the XSLT processing instructions to render the XML in an HTML table.


The article, Simple Log by Jochen Scharr, presents a very effective and simple to use logging class. The logger writes items as an XML file which is ideal for analysis and automated processing with XPath. It can show the XML file in a browser or XML editor but that can be daunting for a user to look at. Especially when talking to a user remotely, it hampers communication. This small extension shows the log entries as a table instead of an XML tree in a browser.

If you are not familiar with the Simple Log class, read the article by Jochen Schurr first!

Sample output of Simple Log

Sample output of simple log entries


Although not often used, XML files can have processing instructions that browsers use to transform the XML. These processing instructions are XSLT stylesheets that can be embedded in the XML. The XML file is still valid and can be processed normally but if opened in a browser, the XSL code is executed before rendering the XML.

Simple Log uses a straightforward XML structure where only exceptions are nested. The XSL creates an HTML table for easy reading of the log entries.

The XSL code and CSS style sheet are embedded in the XML file that is saved with the ShowLogFile method.

  1  <?xml version="1.0" encoding="UTF-8"?>
  2  <xsl:stylesheet xmlns:xsl="" version="1.0">
  3    <xml:comment>XML logger export stylesheet for Chromium and FireFox rendering engines
  4    </xml:comment>
  5    <xsl:output method="html" version="4.0" encoding="ISO-8859-1" indent="no" 
  6     omit-xml-declaration="yes"/>
  7    <xsl:template match="/">
  8    <html>
  9      <head>
 12        <title>Log <xsl:value-of select="/LogEntries/@Date"/></title>
 13        <style media="screen" type="text/css">
 14   body {
 15   background-color: #F1F0EB;
 16   font-family: Verdana, Tahoma, Helvetica, sans-serif;
 17   font-size: .8em;
 18   margin: 10, 10, 10, 10;
 19   }
 21   h1 {
 22   font-size: 12px;
 23   color: #A0A0A0;
 24   }
 26   table {
 27   border-width: 1px;
 28   border-spacing: 2px;
 29   border-style: solid;
 30   border-color: gray;
 31   border-collapse: separate;
 32   background-color: #F1F0EB;
 33   }
 35   table thead {
 36   border-width: 0px;
 37   font-weight: bold;
 38   line-height: 1.2em;
 39   padding: 1px;
 40   border-style: none;
 41   border-color: gray;
 42   background-color: #F1F0EB;
 43   -moz-border-radius: ;
 44   }
 46   table td {
 47   border-width: 0px;
 48   padding: 1px;
 49   line-height: 1.2em;
 50   border-style: none;
 51   border-color: gray;
 52   background-color: white;
 53   -moz-border-radius: ;
 54   }
 55   </style>
 56      </head>
 57        <body>
 58          <h1>Log date: <xsl:value-of select="/LogEntries/@Date"/> 
 59          [<xsl:value-of select="count(/LogEntries/LogEntry)"/> entries.]</h1>
 60          <table border="1">
 61            <thead>
 62              <tr bgcolor="#9acd32">
 63                <td>Date Time</td>
 64                <td>Severity / Exception type</td>
 65                <td>Message</td>
 66                <td>Source / ID + Stacktrace</td>
 67                <td>ThreadId</td>
 68              </tr>
 69            </thead>
 70            <tbody>
 71              <xsl:apply-templates select="*"/>
 72            </tbody>
 73          </table>
 74        </body>
 75      </html>
 76    </xsl:template>
 78    <xsl:template match="LogEntry">
 79      <tr>
 80        <td>
 81          <xsl:value-of select="@Date"/>
 82        </td>
 83        <td>
 84          <xsl:value-of select="@Severity"/>
 85        </td>
 86        <xsl:apply-templates select="*"/>
 87        <td>
 88          <xsl:value-of select="@Source"/>
 89        </td>
 90        <td align="center">
 91          <xsl:value-of select="@ThreadId"/>
 92        </td>
 93      </tr>
 94    </xsl:template>
 96    <xsl:template match="LogEntry[@Severity='Exception']">
 97      <tr>
 98        <td>
 99          <xsl:value-of select="@Date"/>
100        </td>
101        <td>
102          <xsl:value-of select="@Severity"/>
103        </td>
104        <td>
105          <i>See details below</i>
106        </td>
107        <td>
108          <xsl:value-of select="@Source"/>
109        </td>
110        <td align="center">
111          <xsl:value-of select="@ThreadId"/>
112        </td>
113      </tr>
114      <xsl:apply-templates select="Exception"/>
115    </xsl:template>
117    <xsl:template match="Message">
118      <td>
119        <xsl:value-of select="."/>
120      </td>
121    </xsl:template>
123    <xsl:template match="Exception">
124      <tr>
125        <td/>
126        <td>
127          <xsl:value-of select="@Type"/>
128        </td>
129        <xsl:apply-templates select="Message"/>
130        <td>
131          <xsl:value-of select="@ID"/>
132          <xsl:value-of select="StackTrace"/>
133        </td>
134        <td/>
135      </tr>
136      <xsl:apply-templates select="Exception"/>
137    </xsl:template>
138  </xsl:stylesheet>

A small piece of code is added to the SimpleLog.cs file to determine the default browser on the target PC so the log file is shown in a browser irrespective of the XML file association.

Using the Code

The code works exactly the same as the original code from Jochen Scharr. The example provided in his article still works but now shows the output as a table in the default browser as shown in the screenshot above.

static void Main(string[] args)
  // Log to a sub-directory 'Log' of the current working directory. 
  // Prefix log file with 'MyLog_'.
  // This is an optional call and has only to be done once, 
  // preferably before the first log entry is written.
  SimpleXmlLog.SetLogFile(".\\Log", "MyLog_");
  // Write info message to log
  SimpleXmlLog.Info("Test logging started.");
  // Write warning message to log
  SimpleXmlLog.Warning("This is a warning.");
  // Write error message to log
  SimpleXmlLog.Error("This is an error.");
    // For demonstration, do logging in sub-method, throw an exception,
    // catch it, wrap it in another exception and throw it.
  catch(Exception ex)
    // Write exception with all inner exceptions to log
  // Show log file as a table in the default browser
private static void DoSomething()
  SimpleXmlLog.Info("Entering method. See Source which method is meant.");
  catch(Exception ex)
    throw new InvalidOperationException("Something went wrong.", ex);
private static void DoSomethingElse(string fred)
  SimpleXmlLog.Info("Entering method. See Source which method is meant.");
    // Purposely provoking an exception.
    int a = fred.IndexOf("Hello");
  catch(Exception ex)
    throw new Exception("Something went wrong.", ex);

Points of Interest

Apart from adding the processing instructions to the exported XML, Jochen Schurr comments in the source code were reformatted so the help compiler output would look nicer.


  • 20th February, 2021: Updated source

Be sure to read the original article by Jochen Schurr to understand the details of using the Simple Log class.


This article, along with any associated source code and files, is licensed under The MIT License


About the Author

Software Developer (Senior) Infolution
Netherlands Netherlands
Information architect focussed on solving information complexity.
Developer of information retrieval systems. Making computers understand text in a human like way through machine learning, semantic analysis, entity extraction and opinion mining.

Comments and Discussions

PraiseCool! Pin
Jochen Scharr22-Feb-21 0:59
MemberJochen Scharr22-Feb-21 0:59 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.