diff --git a/src/add-sfxmetricdata.ps1 b/src/add-sfxmetricdata.ps1 new file mode 100644 index 0000000..91c330a --- /dev/null +++ b/src/add-sfxmetricdata.ps1 @@ -0,0 +1,30 @@ +function Add-SfxMetricData { + [CmdletBinding()] + param ( + [Parameter(Mandatory, ValueFromPipeline)] + [SfxPostDataPoint] + $InputObject, + + [Parameter(Mandatory, Position = 0)] + [long] + $Value, + + [Parameter(Position = 1)] + [hashtable] + $Dimension + ) + + begin { } + + process { + + if ($PSBoundParameters.ContainsKey('Dimension')) { + $InputObject.AddData($Value, $Dimension) + } else { + $InputObject.AddData($Value) + } + + } + + end { } +} \ No newline at end of file diff --git a/src/classes.datapoint.ps1 b/src/classes.datapoint.ps1 new file mode 100644 index 0000000..c6f1940 --- /dev/null +++ b/src/classes.datapoint.ps1 @@ -0,0 +1,60 @@ +class SfxDataPoint { + [hashtable]$dimensions + [string]$metric + [long]$timestamp + [long]$value + + SfxDataPoint([hashtable]$dimensions, [string]$metric, [long]$value) { + $this.dimensions = $dimensions + $this.metric = $metric + $this.value = $value + $this.timestamp = [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds() + } +} + +# https://developers.signalfx.com/ingest_data_reference.html#operation/Send%20Metrics +class SfxPostDataPoint : SFxClientIngest { + [string]$Type + [string]$Metric + [hashtable]$Dimensions + [SfxDataPoint[]]$Data + + SfxPostDataPoint([string]$type, [string]$name) : base('datapoint', 'POST'){ + $this.Type = $type + $this.Metric = $name + $this.Dimensions = @{} + } + + [SfxPostDataPoint] AddDimension ([string]$key, [string]$value) { + $this.Dimensions.Add($key, $value) + + return $this + } + + [SfxPostDataPoint] AddData ([long]$value) { + $this.Data += [SfxDataPoint]::new($this.Dimensions, $this.Metric, $value) + + return $this + } + + [SfxPostDataPoint] AddData ([long]$value, [hashtable]$dimensions) { + $this.Data += [SfxDataPoint]::new($dimensions, $this.Metric, $value) + + return $this + } + + [object] Invoke() { + + $datahash = @{"$($this.Type.ToLower())" = $this.Data} + + $parameters = @{ + Uri = $this.Uri + Headers = $this.Headers + ContentType = 'application/json' + Method = $this.Method + Body = $datahash | ConvertTo-Json -Depth 3 + } + + return Invoke-RestMethod @parameters + } +} \ No newline at end of file diff --git a/src/new-sfxmetric.ps1 b/src/new-sfxmetric.ps1 new file mode 100644 index 0000000..a561b96 --- /dev/null +++ b/src/new-sfxmetric.ps1 @@ -0,0 +1,37 @@ +function New-SfxMetric { + [CmdletBinding()] + param ( + [ValidateSet('Gauge', 'Counter', 'CumulativeCounter')] + [Parameter(Position = 0, Mandatory)] + [string] + $Type, + + [ValidateLength(1,256)] + [Parameter(Position = 1, Mandatory)] + [string] + $Metric, + + [Parameter(Position = 2)] + [hashtable] + $Dimension, + + [Parameter(Position = 3)] + [string] + $ApiToken + + ) + + $sfxMetric = [SfxPostDataPoint]::new($Type, $Metric) + + if ($PSBoundParameters.ContainsKey('Dimension')) { + Foreach ($key in $Dimension.Keys) { + $sfxMetric.AddDimension($key, $Dimension[$key]) | Out-Null + } + } + + if ($PSBoundParameters.ContainsKey('ApiToken')) { + $item.SetToken($ApiToken) | Out-Null + } + + $sfxMetric | Write-Output +} \ No newline at end of file diff --git a/src/publish-sfxmetric.ps1 b/src/publish-sfxmetric.ps1 new file mode 100644 index 0000000..6db4ef5 --- /dev/null +++ b/src/publish-sfxmetric.ps1 @@ -0,0 +1,31 @@ +function Publish-SfxMetric { + [CmdletBinding()] + param ( + [Parameter(Mandatory, ValueFromPipeline)] + [SfxPostDataPoint[]] + $InputObject, + + [Parameter(Position = 1)] + [string] + $ApiToken + ) + + begin { + + } + + process { + foreach ($item in $InputObject) { + + if ($PSBoundParameters.ContainsKey('ApiToken')) { + $item.SetToken($ApiToken) | Out-Null + } + + $item.Invoke() + } + } + + end { + + } +} \ No newline at end of file diff --git a/src/signalfx-powershell.psd1 b/src/signalfx-powershell.psd1 index 6b49b71..bd03da5 100644 --- a/src/signalfx-powershell.psd1 +++ b/src/signalfx-powershell.psd1 @@ -12,7 +12,7 @@ RootModule = 'signalfx-powershell.psm1' # Version number of this module. - ModuleVersion = '0.3.0' + ModuleVersion = '0.3.1' # Supported PSEditions # CompatiblePSEditions = @() @@ -84,6 +84,9 @@ 'Clear-SFxIncident' 'New-SFxSessionToken' 'Get-SFxMetricMetadata' + 'New-SfxMetric' + 'Add-SfxMetricData' + 'Publish-SfxMetric' ) # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. diff --git a/src/signalfx-powershell.psm1 b/src/signalfx-powershell.psm1 index ca1f11c..407cba1 100644 --- a/src/signalfx-powershell.psm1 +++ b/src/signalfx-powershell.psm1 @@ -6,6 +6,7 @@ . "$PSScriptRoot\classes.organization.ps1" . "$PSScriptRoot\classes.incidents.ps1" . "$PSScriptRoot\classes.session.ps1" +. "$PSScriptRoot\classes.datapoint.ps1" . "$PSScriptRoot\get-sfxdimensionmetadata.ps1" . "$PSScriptRoot\get-sfxalertmuting.ps1" @@ -20,4 +21,7 @@ . "$PSScriptRoot\get-sfxincident.ps1" . "$PSScriptRoot\clear-sfxincident.ps1" . "$PSScriptRoot\new-sfxsessiontoken.ps1" -. "$PSScriptRoot\get-sfxmetricmetadata.ps1" \ No newline at end of file +. "$PSScriptRoot\get-sfxmetricmetadata.ps1" +. "$PSScriptRoot\new-sfxmetric.ps1" +. "$PSScriptRoot\add-sfxmetricdata.ps1" +. "$PSScriptRoot\publish-sfxmetric.ps1" \ No newline at end of file diff --git a/tests/add-sfxmetricdata.Tests.ps1 b/tests/add-sfxmetricdata.Tests.ps1 new file mode 100644 index 0000000..39e59de --- /dev/null +++ b/tests/add-sfxmetricdata.Tests.ps1 @@ -0,0 +1,83 @@ +Describe "Add-SFxMetricData" { + + Import-Module "$PSScriptRoot\..\src\signalfx-powershell.psd1" -Force + + InModuleScope -ModuleName 'signalfx-powershell' { + + Context 'Add a metric without Dimensions' { + + It 'Should add a value to object from Pipeline' { + $testmetric = New-SfxMetric -Type Gauge -Metric test.metric + $it = $testmetric | Add-SfxMetricData 1 + + $it.Data | Should -HaveCount 1 + $it.Data.metric | Should -Be 'test.metric' + $it.Data.timestamp | Should -BeGreaterThan 1583351218758 + $it.Data.dimensions | Should -BeNullOrEmpty + $it.Data.value | Should -Be 1 + } + + It 'Should add a value to object as Parameter' { + $testmetric = New-SfxMetric -Type Gauge -Metric test.metric + $it = Add-SfxMetricData -InputObject $testmetric -Value 2 + + $it.Data | Should -HaveCount 1 + $it.Data.metric | Should -Be 'test.metric' + $it.Data.timestamp | Should -BeGreaterThan 1583351218758 + $it.Data.dimensions | Should -BeNullOrEmpty + $it.Data.value | Should -Be 2 + } + + It 'Should add multiple recordings' { + $testmetric = New-SfxMetric -Type Gauge -Metric test.metric + $it = $testmetric | Add-SfxMetricData 1 | Add-SfxMetricData 2 + + $it.Data | Should -HaveCount 2 + $it.Data[0].metric | Should -Be 'test.metric' + $it.Data[0].timestamp | Should -BeGreaterThan 1583351218758 + $it.Data[0].dimensions | Should -BeNullOrEmpty + $it.Data[0].value | Should -Be 1 + + $it.Data[1].metric | Should -Be 'test.metric' + $it.Data[1].timestamp | Should -BeGreaterOrEqual $it.Data[0].timestamp + $it.Data[1].dimensions | Should -BeNullOrEmpty + $it.Data[1].value | Should -Be 2 + } + } + + Context 'Add a metric with Dimensions' { + + It 'Should add a value to object from Pipeline' { + $testmetric = New-SfxMetric -Type Gauge -Metric test.metric + $it = $testmetric | Add-SfxMetricData -Value 1 -Dimension @{host='test_host'} + + $it.Data | Should -HaveCount 1 + $it.Data.metric | Should -Be 'test.metric' + $it.Data.timestamp | Should -BeGreaterThan 1583351218758 + $it.Data.dimensions | Should -HaveCount 1 + $it.Data.dimensions['host'] | Should -Be 'test_host' + $it.Data.value | Should -Be 1 + } + + It 'Should add multiple recordings with different dimensions' { + $testmetric = New-SfxMetric -Type Gauge -Metric test.metric + $it = $testmetric | Add-SfxMetricData 1 @{host='test_host'} | Add-SfxMetricData 2 @{host='test_host2'} + + $it.Data | Should -HaveCount 2 + $it.Data[0].metric | Should -Be 'test.metric' + $it.Data[0].timestamp | Should -BeGreaterThan 1583351218758 + $it.Data[0].dimensions | Should -HaveCount 1 + $it.Data[0].dimensions['host'] | Should -Be 'test_host' + $it.Data[0].value | Should -Be 1 + + $it.Data[1].metric | Should -Be 'test.metric' + $it.Data[1].timestamp | Should -BeGreaterOrEqual $it.Data[0].timestamp + $it.Data[1].dimensions | Should -HaveCount 1 + $it.Data[1].dimensions['host'] | Should -Be 'test_host2' + $it.Data[1].value | Should -Be 2 + } + } + } + + Remove-Module signalfx-powershell +} \ No newline at end of file diff --git a/tests/new-sfxmetric.Tests.ps1 b/tests/new-sfxmetric.Tests.ps1 new file mode 100644 index 0000000..3e77aba --- /dev/null +++ b/tests/new-sfxmetric.Tests.ps1 @@ -0,0 +1,32 @@ +Describe "New-SFxMetric" { + + Import-Module "$PSScriptRoot\..\src\signalfx-powershell.psd1" -Force + + InModuleScope -ModuleName 'signalfx-powershell' { + + Context 'Basic Gauge' { + $it = New-SfxMetric -Type Gauge -Metric test.metric + + It 'Should return a SfxPostDataPoint object' { + $it.GetType().Name | Should -Be 'SfxPostDataPoint' + $it.Type | Should -Be 'Gauge' + $it.Metric | Should -Be 'test.metric' + $it.Dimensions.Count | Should -Be 0 + } + } + + Context 'Counter with Parameters' { + $it = New-SfxMetric -Type Counter -Metric test.metric -Dimension @{host='test_host'} + + It 'Should have additional properties' { + $it.GetType().Name | Should -Be 'SfxPostDataPoint' + $it.Type | Should -Be 'Counter' + $it.Metric | Should -Be 'test.metric' + $it.Dimensions.Count | Should -Be 1 + $it.Dimensions['host'] | Should -Be 'test_host' + } + } + } + + Remove-Module signalfx-powershell +} \ No newline at end of file