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.
Introduction
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 entries
Background
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 ="1.0"="UTF-8"
2 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 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>
10 <meta NAME="ROBOTS" CONTENT="NOINDEX,NOFOLLOW"/>
11 <meta HTTP-EQUIV="PRAGMA" CONTENT="NO-CACHE"/>
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 }
20
21 h1 {
22 font-size: 12px;
23 color: #A0A0A0;
24 }
25
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 }
34
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 }
45
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>
77
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>
95
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>
116
117 <xsl:template match="Message">
118 <td>
119 <xsl:value-of select="."/>
120 </td>
121 </xsl:template>
122
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)
{
SimpleXmlLog.SetLogFile(".\\Log", "MyLog_");
SimpleXmlLog.Info("Test logging started.");
SimpleXmlLog.Warning("This is a warning.");
SimpleXmlLog.Error("This is an error.");
try
{
DoSomething();
}
catch(Exception ex)
{
SimpleXmlLog.Log(ex);
}
SimpleXmlLog.ShowLogFile();
}
private static void DoSomething()
{
SimpleXmlLog.Info("Entering method. See Source which method is meant.");
try
{
DoSomethingElse(null);
}
catch(Exception ex)
{
SimpleXmlLog.Log(ex);
throw new InvalidOperationException("Something went wrong.", ex);
}
}
private static void DoSomethingElse(string fred)
{
SimpleXmlLog.Info("Entering method. See Source which method is meant.");
try
{
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.
History
- 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.