Created
May 9, 2021 23:56
-
-
Save SP3269/d0515ff72c479dbbadbed082b63943f2 to your computer and use it in GitHub Desktop.
Dockerable Prometheus "anything" exporter in PowerShell
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# pwsh "anything" Prometheus exporter sketch | |
# Using: PrometheusExporter (https://github.com/jobec/powershell-prom-client), including class defintitions | |
# Using: Polaris (https://github.com/PowerShell/Polaris) | |
# Motivation: being able to package PowerShell-based collector/exporter in a Docker container | |
# PrometheusExporter's 0.1.0 New-PrometheusExporter functionfails when run in a container - [console]::KeyAvailable error | |
# NOTE: Polaris can process one request at a time. Refactor/implement LB for real use | |
Using module PrometheusExporter | |
Import-Module Polaris | |
# Polaris request logging | |
function Log-Request([PolarisRequest]$Request) { | |
$logentry = '{0} {1} [{2}] "{3}"' -f $Request.clientIP,($Request.user ?? "-"),(Get-Date -Format "yyyy-MM-dd HH:mm:ss"),$Request.URL | |
Write-Host $logentry | |
} | |
New-PolarisRouteMiddleware -Name "Request Logger" -Scriptblock { | |
Log-Request -Request $Request | |
} | |
# The renderer function | |
function Render-Collector ( | |
[Parameter(Mandatory = $true)][ScriptBlock]$Collector | |
) { | |
$ch = [Channel]::new() # A class from PrometheusExporter | |
$ch.AddMetrics($Collector.Invoke()) | |
[String]$ch | |
} | |
# Collector metric descriptors and initial values | |
$global:invocations = 0 | |
$collection_time_desc = New-MetricDescriptor -Name "pwsh_collection_time" -Type gauge -Help "Last collection time (s)" | |
$invocations_desc = New-MetricDescriptor -Name "pwsh_number_of_invocations" -Type counter -Help "Number of collections by this instance" | |
$uptime_desc = New-MetricDescriptor -Name "pwsh_collector_instance_uptime" -Type counter -Help "Exporter instance uptime (s)" | |
$starttime = Get-Date | |
# Custom metrics | |
# Metric 1 - IBM market cap | |
$vkey = "demo" # alphavantage.co API key | |
$IBMMarketCapDesc = New-MetricDescriptor -Name "ibm_market_cap" -Type gauge -Help "IBM market capitalisation" | |
$GetIBMMarketCap = {(Invoke-RestMethod "https://www.alphavantage.co/query?function=OVERVIEW&symbol=IBM&apikey=$vkey" -Verbose).MarketCapitalization} | |
# Metric 2 - 2D random motion | |
$global:x = 0 | |
$global:y = 0 | |
$XYDesc = New-MetricDescriptor -Name "traveler_distance" -Type gauge -Help "Distance from (0,0)" | |
$XYDistance = { | |
$global:x += (-1..1 | Get-Random) | |
$global:y += (-1..1 | Get-Random) | |
[System.Math]::Sqrt($global:x*$global:x+$global:y*$global:y) | |
} | |
# The collector function - outputs Metric[] | |
function collector() { | |
@( | |
$tick = Get-Date | |
New-Metric -MetricDesc $IBMMarketCapDesc -Value (& $GetIBMMarketCap) | |
New-Metric -MetricDesc $XYDesc -Value (& $XYDistance) | |
$tock = Get-Date | |
New-Metric -MetricDesc $collection_time_desc -Value ($tock - $tick).TotalSeconds | |
New-Metric -MetricDesc $invocations_desc -Value (++$global:invocations) | |
New-Metric -MetricDesc $uptime_desc -Value ([math]::Floor(((Get-Date) - $starttime).TotalSeconds) ) | |
) | |
} | |
# The runtime | |
$port = $env:PORT ?? 9070 | |
$starttime = Get-Date | |
$invocationcount = 0 | |
# Not using the exporter's built-in exporter runtime | |
# $exp = New-PrometheusExporter -Port $port | |
# Register-Collector -Exporter $exp -Collector $Function:collector | |
# $exp.Collect() | |
New-PolarisGetRoute -Path "/hello" -Scriptblock { | |
$Response.Send('hello') | |
} | |
New-PolarisGetRoute -Path "/metrics" -Scriptblock { | |
$body = Render-Collector $Function:collector | |
$Response.ContentType = "text/plain; version=0.0.4; charset=utf-8" | |
$Response.Send($body) | |
} | |
$Polaris = Start-Polaris -Port $port | |
while ($Polaris.Listener.IsListening) { | |
Wait-Event callbackeventbridge.callbackcomplete | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment