Kabompo.Logging.ps1

#
# Kabompo.Logging.ps1
#

function Register-KabompoLogging
{
    <#
    .SYNOPSIS
        Starts logging of KABOMPO module.
    .DESCRIPTION
        Initializes the logging to the KABOMPO logfile in the subdirectory "log". Please be sure, that the executing user has write access to this folder.
    .EXAMPLE
        Register-Logging -Name "MyLog" -Extension "log" -MaxSize 5000000 -MaxAge 60
    .EXAMPLE
        Register-Logging
    .NOTES
    .LINK
        https://marketplace.matrix42.com
    #>


    Param
    (
        [Parameter(Mandatory=$false)]
        [string]$Name="kabompo",

        [Parameter(Mandatory=$false)]
        [string]$Extension="log",

        [Parameter(Mandatory=$false)]
        [int]$MaxSize=5000000,

        [Parameter(Mandatory=$false)]
        [int]$MaxAge=60
    )

    $logCount = 1

    try
    {
        $global:kabompoLog = $null

        # Check if path exist
        if(!(Test-Path "$($PSScriptRoot)\log"))
        {
            try
                { $logPath = (New-Item -Path "$($PSScriptRoot)" -Name "log" -ItemType directory).FullName }
            catch
                { $logPath = (New-Item -Path "$($env:TEMP)" -Name "KABOMPO" -ItemType directory).FullName }
        }
        else
            { $logPath = "$($PSScriptRoot)\log" }

        # define the absolute path of the logfile
        $logFile = "{0}\{1}.{2}" -f $logPath, $Name, $Extension

        # get files based on lastwrite filter and specified folder
        $Files = @(Get-ChildItem $logPath -Filter "*.$Extension" | where { $_.LastWriteTime -le ((Get-Date).AddDays(-$MaxAge))})

        # Delete all files older than X days and bigger that Y size
        foreach ($File in $Files) 
            { Remove-Item $File.FullName | Out-Null }

        # Is logfile size more than size X
        $log = @(Get-ChildItem $logPath -Filter "$Name.$Extension" | where { $_.Length -ge $MaxSize })
        
        if($log -ne $null)
        {
            # Find the next free logfile-name
            while ($targetLogName -eq $null) 
            { 
                $testLogName = "{0}_{1}.{2}" -f $Name, $logCount, $Extension
                if(!(Test-Path "$logPath\$testLogName"))
                    { $targetLogName = $testLogName } 
                else 
                    { $logCount++ }
            }
            # Rename logfile
            Rename-Item -Path $logFile -NewName $targetLogName
        }

        # Define logfile-name
        $global:kabompoLog = $logFile

        # Set LogLevel
        if($global:LogDetailLevel -eq $null)
            { $global:LogDetailLevel = 1 }

        Add-KabompoLogLine -Message "----------------- New logfile worker initialized. Start logging ----------------- " -Component Register-KabompoLogging -Type 1
    }
    catch
    {
        throw $_.Exception
    }
}

function Add-KabompoLogLine
{
    <#
    .SYNOPSIS
        Add a line to the KABOMPO logfile.
    .DESCRIPTION
        Add a line to the KABOMPO logfile in the subdirectory "log". Please be sure, that the executing user has write access to this folder.
    .EXAMPLE
        Add-KabompoLogLine -Message "Some message" -Component My-CurrentFunction -Type 1
    .EXAMPLE
        Add-KabompoLogLine -Message "Some message" -ErrorMessage "My detailed error message" -Component My-CurrentFunction -Type 3
    .NOTES
    .LINK
        https://marketplace.matrix42.com
    #>

    Param 
    (
        [Parameter(Mandatory=$true)]
        $Message,
        [Parameter(Mandatory=$false)]
        $ErrorMessage,
        [Parameter(Mandatory=$false)]
        $Component,
        [Parameter(Mandatory=$true)]
        [ValidateSet(1,2,3)] #Type: 1 = Normal, 2 = Warning (yellow), 3 = Error (red)
        [int]$Type,
        [Parameter(Mandatory=$false)]
        [ValidateSet(0,1,2)] #Log Level: 0 = Debug, 1 = Normal, 2 = Minimalistic
        [int]$LogLevel = 1
    )

    # Exit when logging is disabled for unit testing
    if($global:LogDetailLevel -eq 99)
        { return }

    # Exit function when given loglevel is less than configured loglevel
    if($LogLevel -lt $global:LogDetailLevel -and  $Type -eq 1)
        { return }

    # Exit function if idention level is too high for minimalistic loglevel
    if($global:logIndention -ge 1 -and $global:LogDetailLevel -eq 2 -and $Type -eq 1)
        { return }

    # Exit function if idention level is too high for normal loglevel
    if($global:logIndention -ge 2 -and $global:LogDetailLevel -eq 1 -and $Type -eq 1)
        { return }

    # exit function if logging is switched off
    if($LogLevel -eq 3)
        { return }

    # Exit function if no message is given
    if([string]::IsNullOrEmpty($Message) -and [string]::IsNullOrEmpty($ErrorMessage))
        { return }
    
    # Use Errormessage as message when message is empty
    elseif([string]::IsNullOrEmpty($Message) -and ![string]::IsNullOrEmpty($ErrorMessage))
        { $Message = $ErrorMessage }
    
    # Combine Errormessage and Message when both are given
    elseif(![string]::IsNullOrEmpty($Message) -and ![string]::IsNullOrEmpty($ErrorMessage))
        { $Message = "{0}. Details: {1}" -f $Message, $ErrorMessage }

    # Generate Date and Time string for CMTrace and Console Log
    $TimeString = Get-Date -Format "HH:mm:ss.ffffff"
    $DateString = Get-Date -Format "MM-dd-yyyy"

    # If errormessage is given, set message type to error
    if (![string]::IsNullOrEmpty($ErrorMessage)) 
        {$Type = 3}

    # Set default comonent string when not given
    if ([string]::IsNullOrEmpty($Component)) 
        {$Component = "KABOMPO"}
 
    # Configure Log Message output string
    $LogMessage = "<![LOG[{0}]LOG]!><time=""{1}"" date=""{2}"" component=""{3}"" context="""" type=""{4}"" thread="""" file="""">" -f $Message, $TimeString, $DateString, $Component, $Type
    #2016-05-06 OLD: $LogMessage = "<![LOG[$Message $ErrorMessage" + "]LOG]!><time=`"$Time`" date=`"$Date`" component=`"$Component`" context=`"`" type=`"$Type`" thread=`"`" file=`"`">"
    $LogMessage | Out-File -Append -Encoding UTF8 -FilePath $global:kabompoLog

    # Write output also to host when enabled and PS-Host is Console or ISE
    if($global:LogToConsole -eq $true -and ((get-host).Name -eq "ConsoleHost" -or (get-host).Name -eq "Windows PowerShell ISE Host"))
        { Write-KabompoLogToHost -Message $Message -Component $Component -Type $Type -DateString $DateString -TimeString $TimeString }
}

function Write-KabompoLogToHost
{
    <#
    .SYNOPSIS
        Output a line to the Powershell console.
    .DESCRIPTION
        Output a line to the Powershell console. This function is just for internal use and not published in the module.
    .EXAMPLE
        Write-EMLogToHost -Message "Some message" -Component My-CurrentFunction -Type 1 -DateString 2016-05-06 -TimeString 12:39:33.698623
    .NOTES
    .LINK
        https://marketplace.matrix42.com
    #>

    Param 
    (
        [Parameter(Mandatory=$true)]
        [string]$Message,

        [Parameter(Mandatory=$true)]
        [string]$Component,

        [Parameter(Mandatory=$true)]
        [ValidateSet(1,2,3)] #Type: 1 = Normal, 2 = Warning (yellow), 3 = Error (red)
        [int]$Type,

        [Parameter(Mandatory=$true)]
        [string]$DateString,

        [Parameter(Mandatory=$true)]
        [string]$TimeString

    )

    $indent = (37 - $Component.Length) + ($global:logIndention * 2)

    # Output information line to the console with the normal powershell console colors
    $indentMessage = $Message.PadLeft($Message.Length + $indent, " ")
    if($Type -eq 1)
    { 
        $HostMessage = "{0}_{1} I [{2}] {3}" -f $DateString, $TimeString, $Component, $indentMessage
        Write-Host -Object $HostMessage
    }
    # Output warning line to the console in yellow
    elseif($Type -eq 2)
    { 
        $HostMessage = "{0}_{1} W [{2}] {3}" -f $DateString, $TimeString, $Component, $indentMessage
        Write-Host -Object $HostMessage -ForegroundColor Yellow
    }
    # Output error line to the console in red
    elseif($Type -eq 3)
    { 
        $HostMessage = "{0}_{1} E [{2}] {3}" -f $DateString, $TimeString, $Component, $indentMessage
        Write-Host -Object $HostMessage -ForegroundColor Red
    }

}