Skip to content

Instantly share code, notes, and snippets.

@JohnL4
Last active October 10, 2018 18:53
Show Gist options
  • Save JohnL4/09943c4d01d7f1125c3b836764654cbd to your computer and use it in GitHub Desktop.
Save JohnL4/09943c4d01d7f1125c3b836764654cbd to your computer and use it in GitHub Desktop.
Using PowerShell and Apache XSLT to transform XML (semantic) logs into plain text

PowerShell script to wrap a bunch of LogData elements (which, by themselves, taken as a collection, do not constitute a valid XML document) in a single LogEntries element, and then process the resulting document with Apache Xalan.

Note that, even though these files are named “NLog”, this XML has nothing to do with NLog. Our app just happens to use NLog to log a blob of custom XML the app itself creates.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet id="nlog-to-text-transform"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0"
>
<xsl:output method="text" omit-xml-declaration="yes" indent="no"/>
<xsl:template match="/">
<!-- If output is text, we don't need a root element to make it legal XML, nor do we need an explicit line feed.
<nlogText>
<xsl:text>&#10;</xsl:text>
-->
<!-- Root LogEntries element added by pre-processing script.
(Pre-processing also strips out the "XML" processing instructions and restores a single one at the top of the document.)
-->
<xsl:for-each select="LogEntries/LogData">
<xsl:value-of select="SeverityLevel"/>
<xsl:text>&#9;</xsl:text> <!-- Horizontal tab to accommodate different-length severity level labels. -->
<xsl:value-of select="Time"/>
<xsl:text> -- </xsl:text>
<xsl:value-of select="LogMessage"/>
<xsl:text> -- </xsl:text>
<xsl:value-of select="Operation"/>
<xsl:text> -- </xsl:text>
<xsl:value-of select="TypeName"/>
<xsl:text> -- </xsl:text>
<xsl:value-of select="ComponentName"/>
<xsl:text>&#10;</xsl:text> <!-- New line. -->
</xsl:for-each>
<!--
</nlogText>
-->
</xsl:template>
</xsl:stylesheet>
<#
.SYNOPSIS
Transform Sunrise Nlog output (e.g., UIShell.log) to more-readable text
.DESCRIPTION
The UIShell.log file will be found in (for example) c:/ProgramData/Allscripts Sunrise/Helios/8.4/Gateway/Log
#>
param(
[Parameter( Mandatory = $true)]
[string]
# Input nlog file name
$inFileName,
[Parameter( Mandatory = $true)]
[string]
# Output text file name
$outFileName
)
# ---------------------------------------------------- Constants -----------------------------------------------------
$NLOG_XSLT = ls ".\nlog-to-text.xsl"
# Apache Xalan can be obtained at https://xalan.apache.org/ (or Google it).
$XALAN_JAR_PATH = "c:\usr\local\xalan-j_2_7_2\xalan.jar"
# ---------------------------------------------------- Functions -----------------------------------------------------
function Xform-Nlog
{
param(
[Parameter( Mandatory = $true)]
[string]
# Input nlog file name
$inFileName,
[Parameter( Mandatory = $true)]
[string]
# Output text file name
$outFileName
)
# Write-Verbose ("Xform-Nlog -in {0} -out {1}" -f $inFileName, $outFileName)
$tempFile = New-TemporaryFile
Write-Verbose ("Using temporary file {0}" -f $tempFile.FullName)
echo '<?xml version="1.0"?>' > $tempFile
# I can't make the following work in Chrome.
# echo ('<?xml-stylesheet type="text/xsl" href="file:///{0}"?>' -f ($NLOG_XSLT.FullName -replace "\\","/")) >> $tempFile
# Using XSLT to process XML requires the XML be well-formed, and UIShell.log is not. There are several problems:
#
# - No single root-level element
# - Multiple occurrences of the "<?xml" processing instruction.
# - Presence of NUL characters in the nlog output.
#
# So, now we fix that.
#
echo "<LogEntries>" >> $tempFile # Root element
# (Get-Content $inFileName).Replace("`0"," ")
# Strip out processing instructions and NULs.
cat $inFileName `
| Select-String -SimpleMatch -Pattern '<?xml version="1.0"?>' -NotMatch `
| % { $_ -replace "`0"," " } `
>> $tempFile
echo "</LogEntries>" >> $tempFile
# cat $tempFile
# Apply XSLT.
java -jar $XALAN_JAR_PATH -IN $tempFile.FullName -OUT $outFileName -XSL $NLOG_XSLT.FullName
rm $tempFile
# Write-Host -fore Cyan $tempFile.FullName
}
# ------------------------------------------------------- Main -------------------------------------------------------
Xform-Nlog -in $inFileName -out $outFileName
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment