Private/Functions/Logging/File/New-LoggingThread.ps1

function New-LoggingThread
{
    param
    (
        [object]$ThreadArguments
    )

    [scriptblock]$loggingTask = {

        param
        (
            [string]$LogFolder,
            [string]$HttpLogHeader,
            [string]$ErrorLogHeader,
            [System.Collections.Concurrent.BlockingCollection[System.Collections.Generic.KeyValuePair[string, string]]]$LogQueue,
            [System.Threading.CancellationToken]$CancellationToken
        )

        if ([string]::IsNullOrEmpty($LogFolder))
        {
            # Nothing to do
            return
        }

        $httpLogInit = $false
        $errorLogInit = $false
        $utf8Encoding = [System.Text.UTF8Encoding]::new($false)

        while ($true)
        {
            try
            {

                # Queue stores KeyValuePair<string,string> objects as a cheap way for storing a pair of strings
                # Key = http log entry
                # Value = error log entry
                $entry = $LogQueue.Take($CancellationToken)

                $dt = [datetime]::UtcNow.ToString('yyyy-MM-dd HH:mm:ss')

                $httpLogFile = [System.IO.Path]::Combine($LogFolder, 'HTTP', "u_ex$([dateTime]::UtcNow.ToString('yyMMdd')).log")

                if (-not [System.IO.File]::Exists($httpLogFile))
                {
                    # Init new log
                    [System.IO.File]::WriteAllText($httpLogFile, ($HttpLogHeader -f $dt), $utf8Encoding)
                    $httpLogInit = $true
                }
                elseif (-not $httpLogInit)
                {
                    # Restart on same log file
                    [System.IO.File]::AppendAllText($httpLogFile, ($HttpLogHeader -f $dt), $utf8Encoding)
                    $httpLogInit = $true
                }

                [System.IO.File]::AppendAllText($httpLogFile, $entry.Key, $utf8Encoding)

                if ($null -ne $entry.Value)
                {
                    # We handled an error - either HTTP status >= 400 or an unhandled exception was thrown from user code.

                    $errorLogFile = [System.IO.Path]::Combine($LogFolder, 'Error', "error_$([dateTime]::UtcNow.ToString('yyMMdd')).log")

                    if (-not [System.IO.File]::Exists($errorLogFile))
                    {
                        # Init new log
                        [System.IO.File]::WriteAllText($errorLogFile, ($ErrorLogHeader -f $dt), $utf8Encoding)
                        $errorLogInit = $true
                    }
                    elseif (-not $errorLogInit)
                    {
                        # Restart on same log file
                        [System.IO.File]::AppendAllText($errorLogFile, ($ErrorLogHeader -f $dt), $utf8Encoding)
                        $errorLogInit = $true
                    }

                    [System.IO.File]::AppendAllText($errorLogFile, $entry.Value, $utf8Encoding)
                }
            }
            catch [System.OperationCanceledException]
            {
                # Server terminating
                return
            }
            catch
            {
                Write-EventLog -LogName Application -Source PowerShellRest -EntryType Error -EventId 100 -Message "Logging Thread`n$($_.Exception.Message)`n`n$($_.Exception.GetType().FullName)`n$($_.ScriptStackTrace)"
                # Do nothing for now.
            }
        }
    }

    # Set up log folders
    Initialize-LogFolder -LogFolder $LogFolder

    $moduleInfo = $MyInvocation.MyCommand.Module

    # Create logging thread
    Write-OperatingSystemLogEntry -EventId ([EventId]::InitializationStep) -Message "Creating logging thread."

    $powershell = [powershell]::Create()

    # Add it's code from the scriptblock
    $powershell.AddScript($loggingTask.ToString()).
        AddArgument($ThreadArguments.LogFolder).
        AddArgument([HttpLogEntry]::GetLogHeader($moduleInfo)).
        AddArgument([ErrorLogEntry]::GetLogHeader($moduleInfo)).
        AddArgument($SharedVariables.LoggingQueue).
        AddArgument($ThreadArguments.CancellationTokenSource.Token) | Out-Null

    # Return the thread
    $powershell
}