include/Seq.ps1

@{
    Name          = 'Seq'
    Description   = 'Sends log data to the designated Seq server web service'
    Configuration = @{
        Url        = @{Required = $true; Type = [string]; Default = $null }
        ApiKey     = @{Required = $false; Type = [string]; Default = $null }
        Properties = @{Required = $false; Type = [hashtable]; Default = $null }
        Level      = @{Required = $false; Type = [string]; Default = $Logging.Level }
    }
    Logger        = {
        param(
            [hashtable] $Log,
            [hashtable] $Configuration
        )
    
        $allProperties = @{}
        if($null -ne $Configuration.Properties)
        {
            $allProperties += $Configuration.Properties
        }

        # use all properies from log
        $allProperties += $Log
        
        # remove not needed values (dont need to safe data twice)
        $allProperties.Remove("args")
        $allProperties.Remove("message")
        $allProperties.Remove("level")
        $allProperties.Remove("levelno")
        $allProperties.Remove("rawmessage")
        $allProperties.Remove("timestamp")
        $allProperties.Remove("timestamputc")
        $allProperties.Remove("execinfo")

        # default use the already parsed message
        $messageTemplate = $Log.Message

        # check if there are any args given
        if ($Log.args.count -gt 0) {
            # args are given, use the raw message with {...} text
            $messageTemplate = $Log.RawMessage;

            # check if labels are given (same amount of labels are args are necessary)
            $labels_given = ($null -ne $Log.body.labels -and $Log.args.count -eq $Log.body.labels.count)

            foreach($argument in $Log.args) {
                if($labels_given) {
                    # labels are given, add the argument as a value and the label as the named index
                    $allProperties.Add($Log.body.labels[$Log.args.IndexOf($argument)], $argument)
                    # replace the messagetemplated e.g. {0} -> {named}
                    $messageTemplate = $messageTemplate.replace("{$($Log.args.IndexOf($argument))}", "{$($Log.body.labels[$Log.args.IndexOf($argument)])}")
                } else {
                    # no labels are given, add the number as an argument so seq can handle the text correctly
                    $allProperties.Add("$($Log.args.IndexOf($argument))", $argument)
                }
            }

            # remove the labels, they have added to allProperties already
            if($labels_given) {
                $allProperties.body.Remove("labels")
            }

        } else {
            $allProperties += @{ Text = $Log.Message; }
        }

        # if body is empty, remove it
        if($allProperties.body.count -eq 0) {
            $allProperties.Remove("body")
        }

        # exception handling
        $exception = $null
        if ($Log.ExecInfo) {
            $exception = $Log.ExecInfo.ToString()
            $exception += [System.Environment]::NewLine + $Log.ExecInfo.ScriptStackTrace
        }

        # use the
        $Body = @{
            "Events" = @(
                @{
                    "Timestamp" = $Log.TimestampUtc
                    "Level" = $Log.Level.substring(0,1).toupper()+$Log.Level.substring(1).tolower()
                    "MessageTemplate" = $messageTemplate
                    "Properties" = $allProperties
                    "Exception" = $exception
                }
            )
        }

        $Body | ConvertTo-Json -Depth 5 | Out-File -FilePath C:\test.json

        if ($Configuration.ApiKey) {
            $Url = '{0}/api/events/raw?apiKey={1}' -f $Configuration.Url, $Configuration.ApiKey
        }
        else {
            $Url = '{0}/api/events/raw' -f $Configuration.Url
        }

        Invoke-RestMethod -Uri $Url -Body ($Body | ConvertTo-Json -Compress -Depth 5) -Method POST -ContentType "application/json" | Out-Null
    }
}