psgraphitemetrics.psm1
<# Module created by ModuleForge ModuleForge Version: 1.0.1 BuildDate: 2025-02-17T09:27:46 #> 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 Changelog: 2025-05-07 - AA - Created the file #> [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() .NOTES Author: Adrian Andersson Changelog: 2025-02-06 - AA - Created function #> [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 Changelog: 2025-02-06 - AA - Created Function #> [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 } } |