Skip to content

Commit

Permalink
Merge pull request #5 from briantist/udp/pipelining
Browse files Browse the repository at this point in the history
Add pipeline support to speed up large numbers of metrics
  • Loading branch information
muratiakos authored Jul 26, 2020
2 parents e2af6f6 + 8b3a2b2 commit 07794f0
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 30 deletions.
2 changes: 1 addition & 1 deletion DogStatsD.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
RootModule = 'DogStatsD.psm1'

# Version number of this module.
ModuleVersion = '1.0.0.0'
ModuleVersion = '1.1.0.0'

# ID used to uniquely identify this module
GUID = 'a2c94f92-cfb1-4f8f-8cc8-7a77b2122b0d'
Expand Down
72 changes: 50 additions & 22 deletions Functions/Send-DataDogMetric.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,29 @@
Send-DataDogMetric -Type Histogram -Name 'command.duration' -Value 12 -Tag @("command:my_command_name")
.EXAMPLE
Send-DataDogMetric -Type Gauge -Name 'random.value' -Value $randomvalue -ComputerName 192.168.0.1 -Port 8125
.EXAMPLE
1..20000 | Send-DataDogMetric -Type Counter -Name 'incrementing.value' -Value { $_ }
.EXAMPLE
Get-AppStatistics | Send-DataDogMetric -Type Gauge -Name 'appco.active_users' -Value { $_.ActiveUsers }
.EXAMPLE
Get-Process |
Send-DataDogMetric -Name 'server.process.handles' -Type Counter -Value { $_.Handles } -Tag { @("process:$($_.ProcessName)","pid:$($_.Id)") }
#>
function Send-DataDogMetric {
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter(Mandatory)]
[Parameter(Mandatory, ValueFromPipelineByPropertyName)]
[Alias('MetricName')]
[ValidateNotNullOrEmpty()]
[string]$Name,

[Parameter(Mandatory)]
[Parameter(Mandatory, ValueFromPipelineByPropertyName)]
[Alias('MetricValue')]
[ValidateNotNullOrEmpty()]
[string]$Value,

[Parameter(Mandatory)]
[Parameter(Mandatory, ValueFromPipelineByPropertyName)]
[Alias('MetricType')]
[ValidateSet('Counter','Gauge','Histogram','Timer','Set','Distribution')]
[string]$Type,

Expand All @@ -52,32 +62,50 @@ function Send-DataDogMetric {
[ValidateRange(1,65535)]
[int]$Port,

[Parameter()]
[Parameter(ValueFromPipelineByPropertyName)]
[Alias('MetricSampleRate')]
[string]$SampleRate='1',

[Parameter()]
[Parameter(ValueFromPipelineByPropertyName)]
[Alias('MetricTag')]
[Alias('MetricTags')]
[string[]]$Tag=@()

)
$ddType = if ($Type -eq 'Timer') {
'ms'
}
else {
$Type.ToLower()[0]
}

$data = "$($Name):$($Value)|$ddType|@$SampleRate|#$([string]::Join(',',$Tag))"
$statsdParams = @{
Data = $data
}
if ($ComputerName) {
$statsdParams.ComputerName = $ComputerName
Begin {
$statsdParams = @{
Verbose = $VerbosePreference -as [bool]
Debug = $DebugPreference -as [bool]
}
if ($ComputerName) {
$statsdParams.ComputerName = $ComputerName
}
if ($Port) {
$statsdParams.Port = $Port
}

# start a steppable pipeline for Send-StatsD so we can ensure we use a single UDP socket across the pipeline
$sendStatsD = { Send-StatsD @statsdParams }.GetSteppablePipeline($MyInvocation.CommandOrigin)
$sendStatsD.Begin($true)
}
if ($Port) {
$statsdParams.Port = $Port

Process {
$ddType = if ($Type -eq 'Timer') {
'ms'
}
else {
$Type.ToLower()[0]
}

$tagData = [string]::Join(',', $Tag)
$data = "${Name}:${Value}|${ddType}|@${SampleRate}|#${tagData}"

if ($PSCmdlet.ShouldProcess($data)) {
$sendStatsD.Process($data)
}
}

if ($PSCmdlet.ShouldProcess("Sending DataDog metric: $data")) {
Send-StatsD @statsdParams
End {
$sendStatsD.End()
}
}
14 changes: 9 additions & 5 deletions Functions/Send-StatsD.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,12 @@ function Send-StatsD {
[int]$Port=8125
)

Process {
Begin {
Write-Verbose "Targeting $($ComputerName):$Port UDP endpoint.."
$UdpClient = New-Object System.Net.Sockets.UdpClient($ComputerName, $Port)
}

Process {
try {
Write-Debug "Encoding data:`n$Data"
$bytes=[System.Text.Encoding]::ASCII.GetBytes($Data)
Expand All @@ -55,13 +57,15 @@ function Send-StatsD {
$sent=$UdpClient.Send($bytes,$bytes.length)
Write-Debug "Data Length sent: $sent"
}
$UdpClient.Close()
} catch {
}
catch {
Write-Error $_
} finally {
$UdpClient.Dispose()
}
}

End {
$UdpClient.Close()
$UdpClient.Dispose()
$UdpClient = $null
}
}
13 changes: 11 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ DogStatsD module provides a simple way to send events and metrics or other
messages to [DataDog][datadog] from PowerShell via [DogStatsD][dogstatsd] UDP protocol.

## Installation
DogStatsD is available via [PowerShellGallery][PowerShellGallery] and via
[PsGet][psget], so you can simply install it with the following command:
DogStatsD is available via [PowerShellGallery][PowerShellGallery], so you can simply install it with the following command:
```powershell
Install-Module DogStatsD
```
Expand All @@ -28,6 +27,16 @@ Send-DataDogMetric -Type Histogram -Name 'command.duration' -Value 12 -Tag @("co
# Send a Gauge metric with value from variable to a given host and port
Send-DataDogMetric -Type Gauge -Name 'random.value' -Value $randomvalue -ComputerName 192.168.0.1 -Port 8125
# Send lots of Counter metric values via the pipeline
1..20000 | Send-DataDogMetric -Type Counter -Name 'incrementing.value' -Value { $_ }
# Use the output of another command to provide values for a Gauge metric
Get-AppStatistics | Send-DataDogMetric -Type Gauge -Name 'appco.active_users' -Value { $_.ActiveUsers }
# Use input objects to generate tags and values for a Counter metric
Get-Process |
Send-DataDogMetric -Name 'process.handles' -Type Counter -Value { $_.Handles } -Tag { @("process:$($_.ProcessName)","pid:$($_.Id)") }
```

## Documentation
Expand Down

0 comments on commit 07794f0

Please sign in to comment.