psgraphitemetrics.psm1
|
<# Module created by ModuleForge ModuleForge Version: 1.2.0 BuildDate: 2025-07-23T12:20:45 #> class UnixTimeStamp { [long]$Timestamp UnixTimeStamp([long]$timestamp){ $this.Timestamp = $timestamp } UnixTimeStamp([datetime]$dateTime){ $timestampConvert = [int][double]::Parse((Get-Date $dateTime -UFormat %s)) $this.Timestamp = $timestampConvert } UnixTimeStamp(){ $timestampConvert = [int][double]::Parse((Get-Date -UFormat %s)) $this.Timestamp = $timestampConvert } [string] ToString() { return "$($this.Timestamp)" } [dateTime] ToDateTime() { return [datetime]::UnixEpoch.AddSeconds($this.Timestamp) } [dateTime] ToLocalDateTime() { $dateTime = [datetime]::UnixEpoch.AddSeconds($this.Timestamp) $timezone = [System.TimeZoneInfo]::Local return [System.TimeZoneInfo]::ConvertTime($dateTime, $timezone) } } class GraphiteMetric { [string]$metricName [double]$metricValue [unixTimeStamp]$timestamp GraphiteMetric([string]$metricName,[double]$metricValue){ $this.metricName = $metricName $this.metricValue = $metricValue $this.timestamp = [unixTimeStamp]::new() } GraphiteMetric([string]$metricName,[double]$metricValue,[datetime]$dateTime){ $this.metricName = $metricName $this.metricValue = $metricValue $this.timestamp = [unixTimeStamp]::new($dateTime) } GraphiteMetric([string]$metricName,[double]$metricValue,[unixTimeStamp]$unixTimeStamp){ $this.metricName = $metricName $this.metricValue = $metricValue $this.timestamp = $unixTimeStamp } GraphiteMetric([string]$metricName,[double]$metricValue,[long]$unixTimeStamp){ $this.metricName = $metricName $this.metricValue = $metricValue $this.timestamp = [unixTimeStamp]::new($unixTimeStamp) } [string] ToGraphite(){ return "$($this.metricName) $($this.metricValue.toString()) $($this.timestamp.ToString())" } } class MetricList : System.Collections.Generic.List[object] { MetricList() : base() {} [void] AddMetric([GraphiteMetric]$metric) { $this.Add($metric) } [void] AddMetric([string]$metricName, [double]$metricValue, [datetime]$dateTime) { $metric = [GraphiteMetric]::new($metricName, $metricValue, $dateTime) $this.Add($metric) } [void] AddMetric([string]$metricName, [double]$metricValue, [UnixTimeStamp]$unixTimeStamp) { $metric = [GraphiteMetric]::new($metricName, $metricValue, $unixTimeStamp) $this.Add($metric) } [void] AddMetric([string]$metricName, [double]$metricValue, [long]$timestamp) { $metric = [GraphiteMetric]::new($metricName, $metricValue, $timestamp) $this.Add($metric) } [void] AddMetric([string]$metricName, [double]$metricValue) { $metric = [GraphiteMetric]::new($metricName, $metricValue) $this.Add($metric) } [string] ToGraphiteString() { $list = $this | ForEach-Object { $_.toGraphite() } $listJoin = $list -join "`n" return $listJoin } } function Export-GraphiteMetricToFile { <# .SYNOPSIS Export all the metrics in a MetricList to a temporary file. Return the filepath .DESCRIPTION Provide a list of graphite metrics in the form of a MetricList. This function will flatten the list into a graphite compatible format and save it as a UTF8, LF line ending file. Will return the file path so you can bundle it up into a rest method to your metric collector ------------ .EXAMPLE #Make an empty metric list $MetricList = new-graphiteMetricList #Add some metrics to your metric list, use the current DateTime stamp as the timestamp $MetricList.addMetric('my.test.metric',41.3) $MetricList.addMetric('my.test.metric2',45.3) $MetricList.addMetric('my.test.metric3',65324) #Export to file and capture the file path $metricFile = Export-GraphiteMetricToFile -MetricList $MetricList .NOTES Author: Adrian Andersson #> [CmdletBinding()] PARAM( #A metric list option. use new-graphiteMetricList to make one [Parameter(Mandatory,ValueFromPipeline)] [MetricList]$MetricList, #Allow Override of the temp file path [Parameter(DontShow)] [string]$TempFilePath ) begin{ #Return the script name when running verbose, makes it tidier write-verbose "===========Executing $($MyInvocation.InvocationName)===========" #Return the sent variables when running debug Write-Debug "BoundParams: $($MyInvocation.BoundParameters|Out-String)" if(!$TempFilePath) { $TempFilePath = "$([System.IO.Path]::GetTempFileName().Replace('.', '')).txt" write-verbose "Temp File will be: $TempFilePath" }else{ write-verbose "Temp file override to: $TempFilePath" } } process{ #Use the inbuilt object method to flatten to the right format write-verbose "Flattening metric data. $($MetricList.count) items to flatten" $metricDataFlat = $MetricList.toGraphite() write-verbose "Outputting content to file: $TempFilePath" #Graphite Files need to specificaly have LF file endings, and it seems safest to force uft8 $metricDataFlat -join "`n"|Set-Content -path $TempFilePath -NoNewline -Force -Encoding utf8 write-verbose 'return Temp File path' $TempFilePath } } function New-GraphiteMetric { <# .SYNOPSIS Creates a new GraphiteMetric object with the specified metric name, value, and optional timestamp. .DESCRIPTION The New-GraphiteMetric function allows you to create a GraphiteMetric object, which represents a metric with a name, value, and timestamp. The function supports multiple ways to specify the timestamp, including a Datetime object, a UnixTimeStamp object, or a Unix timestamp in seconds. If no timestamp is provided, the current date and time are used. .EXAMPLE # Create a GraphiteMetric with the current timestamp $metric = New-GraphiteMetric -MetricName "cpu.usage" -MetricValue 75 Write-Output $metric.toGraphite() .EXAMPLE # Create a GraphiteMetric with a specific Datetime $metric = New-GraphiteMetric -MetricName "memory.usage" -MetricValue 512 -Datetime (Get-Date "2025-02-06T14:00:00") Write-Output $metric.toGraphite() .EXAMPLE # Create a GraphiteMetric with a UnixTimeStamp object $UnixTimeStamp = [UnixTimeStamp]::new(1672531199) $metric = New-GraphiteMetric -MetricName "disk.usage" -MetricValue 1024 -UnixTimeStamp $UnixTimeStamp Write-Output $metric.toGraphite() .EXAMPLE # Create a GraphiteMetric with a Unix timestamp in seconds $metric = New-GraphiteMetric -MetricName "network.usage" -MetricValue 300 -timestamp 1672531199 Write-Output $metric.toGraphite() .OUTPUTS [GraphiteMetric] Output will be a custom GraphiteMetric object .NOTES Author: Adrian Andersson #> [CmdletBinding(DefaultParameterSetName = 'default')] PARAM( #Metric Name / metric path: This is a period-delimited path that identifies the thing being measured, such as 'servers.prod.memory.free' [Parameter(Mandatory,ParameterSetName = 'default')] [Parameter(Mandatory,ParameterSetName = 'Datetime')] [Parameter(Mandatory,ParameterSetName = 'UnixTimeStamp')] [Parameter(Mandatory,ParameterSetName = 'TimeStampString')] [Alias('MetricPath','Metric')] [string]$MetricName, #Value of the metric, anything numeric. Is a long since decimals and ints are valid usually, so lets force decimals to make life easier [Parameter(Mandatory,ParameterSetName = 'default')] [Parameter(Mandatory,ParameterSetName = 'Datetime')] [Parameter(Mandatory,ParameterSetName = 'UnixTimeStamp')] [Parameter(Mandatory,ParameterSetName = 'TimeStampString')] [Alias('value')] [double]$MetricValue, [Parameter(Mandatory,ParameterSetName = 'Datetime')] [Datetime]$Datetime, [Parameter(Mandatory,ParameterSetName = 'UnixTimeStamp')] [UnixTimeStamp]$UnixTimeStamp, [Parameter(Mandatory,ParameterSetName = 'TimeStampString')] [string]$TimeStampString ) begin{ #Return the script name when running verbose, makes it tidier write-verbose "===========Executing $($MyInvocation.InvocationName)===========" #Return the sent variables when running debug Write-Debug "BoundParams: $($MyInvocation.BoundParameters|Out-String)" } process{ switch ($PSCmdlet.ParameterSetName) { 'Datetime' { write-verbose 'Creating with Datetime' return [GraphiteMetric]::new($MetricName, $MetricValue, $Datetime) } 'UnixTimeStamp' { write-verbose 'Creating with UnixTimeStamp object' return [GraphiteMetric]::new($MetricName, $MetricValue, $UnixTimeStamp) } 'TimeStampString' { write-verbose 'Creating with a UnixTime, will convert string to long' return [GraphiteMetric]::new($MetricName, $MetricValue, [long]$TimeStampString) } default { write-verbose 'Creating with current Datetime' return [GraphiteMetric]::new($MetricName, $MetricValue) } } } } function New-GraphiteMetricList { <# .SYNOPSIS Creates a new instance of the MetricList class. .DESCRIPTION The New-MetricList function creates a new instance of the MetricList class, which is a specialized list designed to hold GraphiteMetric objects. This function initializes an empty MetricList that can be used to store and manage multiple GraphiteMetric objects. .EXAMPLE # Create an empty MetricList $metricList = New-MetricList Write-Output $metricList .EXAMPLE # Create a MetricList and add a GraphiteMetric to it $metricList = New-MetricList $metricList.AddMetric("cpu.usage", 75) Write-Output $metricList.ToGraphiteString() .NOTES Author: Adrian Andersson #> [CmdletBinding()] PARAM( ) begin{ #Return the script name when running verbose, makes it tidier write-verbose "===========Executing $($MyInvocation.InvocationName)===========" #Return the sent variables when running debug Write-Debug "BoundParams: $($MyInvocation.BoundParameters|Out-String)" } process{ write-verbose 'Creating Metriclist' $list = [metricList]::new() write-verbose "$($list.GetType()|out-string)" #return $object #$list = [System.Collections.Generic.List[object]]::new() #write-verbose "$($list.GetType()|out-string)" #write-verbose "This should have been a generic list" #See that little comma, it's important #This tells PowerShell we want to treat the return as a single-item Array, and thus preserve it's type information #If we DO NOT include the comma, you never get the resuts of an empty list #And even MORE strange, returning a list that has items in it converts it to a fixed-size array and not a list # How strange is that #Anyway, leave the comma alone ok... It is supposed to be there , $list } } |