Creating a logging framework in PowerShell – Part 2


Just to clarify, a framework is the basic structure underlying a concept or to paraphrase, a framework defines a set of guidelines which when implemented are known to produce beneficial results.

In the first part; we looked a little bit at why logging was important, established a rudimentary of set guidelines to help us log the script actions and also started taking first steps in our journey to creating a logging framework. So, onwards we move.

The last script block we looked at in the first part, we defined various message types that we wanted to log, we also define an array of severity descriptors and we defined a default logging level that can be overridden during initialization.

Since, one of the goals we set at the onset was to keep it simple; we should not be asking the user where the log file will be created by default, but, at the same time we should be flexible enough to accept any valid path they provide to setup the log file. So, let us by default use the module name and location for log file name. Oh! and the log file always have ‘.log’ extension. The code to do this would be:

# By Default use module name and location for LogFile Name and Script Name.
# Caller should instantiate Logger object and set file properties based on script name.
$SCRIPT:LogFileName = [System.IO.Path]::GetFilenameWithoutExtension($MyInvocation.MyCommand.Path.ToString())
$SCRIPT:ScriptName = [System.IO.Path]::GetFilenameWithoutExtension($MyInvocation.MyCommand.Path.ToString())
$SCRIPT:LogFileName += '.log'


The other thing we could do is maintain only a limited number of logfiles. Truth be told, having 200 logfiles is not going to help unless, you are looking for an anamoly that concerns counting. So, our code above gets a new line that can tell us how many log files we want. Again, we can use a default value if the user cannot be bothered or allow the user to manage this number if they are interested in this.

[int]$SCRIPT:NumOfArchives = 10

Now that we have some of the groundwork prepared, let us attmept to write a funciton that will eventually write the messages to the log file. At this point you might be thinking, should I be logging everything? Not necessarily. In order to avoid an overflow of information we will only log messages that have a severity level greater than or equal to the logging level we defined earlier. Also, not only should we write the messages to the log file, we also need to display the information on the host as well. In order to display the information on the host, we will write Information in magenta, warnings in yellow and errors in red.

Function Write-Log {
<#
  .SYNOPSIS
     Write a message to the Log file.
  .DESCRIPTION
    Logs a message to the logfile if the severity is higher than or equal to $LogLevel.
	Default severity level is information.
  .PARAMETER scriptName
     Name of the script/program to be used with logged messages.
     Use the $MSGTYPE_XXXX constants.
  .PARAMETER logName
     Full Name of the file where messages will be written.
  .PARAMETER severity
     The severity of the message.  Can be Information, Warning, or Error.
     Use the $MSGTYPE_XXXX constants.
  .PARAMETER message
     A string to be printed to the log.

  .EXAMPLE
     Write-Log $MSGTYPE_ERROR "Something has gone terribly wrong!"
#>
  	param(
        [string]
        $scriptName = $SCRIPT:ScriptName,
        [string]
        $logName = $SCRIPT:LogFileName,
        [Parameter(Mandatory=$true)]
        [int]
        [ValidateScript({$MSGTYPE_INFORMATION, $MSGTYPE_WARNING, $MSGTYPE_ERROR -contains $_})]
        $severity,
        [Parameter(Mandatory=$true)]
        [string]
        $message
    )
	try
	{
		if ($severity -ge $LogLevel)
		{
			$timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
			$callerName = (Get-PSCallStack)[2].InvocationInfo.MyCommand.Name
			$output = "$timestamp`t`[$($SEVERITY_DESC[$severity])`]: ($callerName)`t$message"

			Write-Output $output >> $logName

			switch($severity)
			{
				$MSGTYPE_INFORMATION {Write-Host $output -Fore Magenta; break}
				$MSGTYPE_WARNING 	{Write-Host $output -Fore Yellow; break}
				$MSGTYPE_ERROR 	    {Write-Host $output -Fore Red; break}
			}
		}
	}
	catch
	{
		$ex = $_.Exception
		$excMsg = $ex.Message.ToString()
		Write-Host "[Write-Log]: "$excMsg -Fore Red

		while ($ex.InnerException)
		{
			$ex = $ex.InnerException
			$excMsg = $ex.InnerException.Message.ToString()
			Write-Host "`t" $ex.InnerException.Message -Fore Red
		}
	}
}


In the next part we will talk about managing the log files. All the fun stuff with sweeping the files and keeping the correct number of log files available, so on and so forth.

Advertisements
About

By profession, I’m a SQL Server Database Administrator. I love to poke my nose into different corners and see how stuff looks in there. I keep looking for new things to do as my mind refuses to settle on one topic.

Tagged with: , , , ,
Posted in PowerShell

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: