PowerShellでMackerelにホストメトリックを投稿する

この記事は Mackerel Advent Calendar 2023 の7日目です。

qiita.com

6日目は id:minemuracoffee さんでした。

www.minemura-coffee.com

本題

ホストメトリックの投稿API を利用するとMackerel Agentを介さずにホストメトリックを投稿することができます。

お馴染みのcurlコマンドだとこんな感じですね。

curl https://api.mackerelio.com/api/v0/tsdb \
  -X POST \
  -H 'X-Api-Key: MACKEREL_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '[
    {"hostId": "HOST_ID", "name": "Sample.foo", "time": '$(date +%s)', "value": 30},
    {"hostId": "HOST_ID", "name": "Sample.bar", "time": '$(date +%s)', "value": 100}
  ]'

まずは上記の例をそのままPowerShellにしてみましょう。

Invoke-WebRequest -Uri https://api.mackerelio.com/api/v0/services/SERVICE_NAME/tsdb `
  -Method Post `
  -Headers @{
    "X-Api-Key" = "MACKEREL_API_KEY"
    "Content-Type" = "application/json"
  } `
  -Body (@(
    @{ hostId = "HOST_ID"; name = "Sample.foo"; time = [int64](Get-Date -UFormat %s); value = 30 },
    @{ hostId = "HOST_ID"; name = "Sample.bar"; time = [int64](Get-Date -UFormat %s); value = 100 }
  ) | ConvertTo-Json)

リクエストボディはパイプでInvoke-WebRequestコマンドレットに渡すことができるので、このように書き換えられます。

@(
  @{ hostId = "HOST_ID"; name = "Sample.foo"; time = [int64](Get-Date -UFormat %s); value = 30 },
  @{ hostId = "HOST_ID"; name = "Sample.bar"; time = [int64](Get-Date -UFormat %s); value = 100 }
) |
ConvertTo-Json |
Invoke-WebRequest -Uri https://api.mackerelio.com/api/v0/services/SERVICE_NAME/tsdb `
  -Method Post `
  -Headers @{
    "X-Api-Key" = "MACKEREL_API_KEY"
    "Content-Type" = "application/json"
  }

つまり次のように一般化できそうです。

何かを | いじって | ConvertTo-Json | Invoke-WebRequest ...

いくつか例を挙げてみましょう。 なお今回はグラフ定義については割愛するため、必要に応じて グラフ定義の投稿API を参照して設定してください。

  • CPU使用率上位5プロセス
Get-Process |
Select-Object `
  @{Name="hostId";Expression={"HOST_ID"}},
  @{Name="name";Expression={"Process." + $_.ProcessName}},
  @{Name="value";Expression={$_.CPU}},
  @{Name="time";Expression={[int64](Get-Date -UFormat %s)}} |
Sort-Object -Property value -Bottom 5 |
ConvertTo-Json |
iwr ...
  • mackerel-agentプロセスのメモリ使用量

(...).PSObject.Properties.GetEnumerator()のところはもうちょっとなんとかしたかったがわからんかった…

(
  Get-Process mackerel-agent |
  Select-Object -Property PagedMemorySize64, PagedSystemMemorySize64, PeakPagedMemorySize64
).PSObject.Properties.GetEnumerator() |
ForEach-Object {
  @{
    hostId = "HOST_ID"
    name = "mackerel-agent.memory." + $_.Name
    value = $_.Value
    time = [int64](Get-Date -UFormat %s)
  }
} |
ConvertTo-Json |
iwr ...
  • mackerel-agentサービスの稼働(Runningなら1、それ以外なら0)

1要素だと配列にならないので先頭にカンマが要る謎仕様…

,@(@{
  hostId = "HOST_ID"
  name = "mackerel-agent.status.running"
  value = if ((Get-Service mackerel-agent).Status -eq "Running") { 1 } else { 0 }
  time = [int64](Get-Date -UFormat %s)
}) |
ConvertTo-Json |
iwr ...

こういうのだとやはりグラフ定義を利用してまとめて表示したくなりますね。

(Get-Counter "\FileSystem Disk Activity(*)\*").CounterSamples | 
Select-Object `
  @{Name="hostId";Expression={"HOST_ID"}},
  @{Name="name";Expression={"FileSystemDiskActivity." + $_.InstanceName + "." + $_.Path.Split(" ")[-1]}},
  @{Name="value";Expression={$_.CookedValue}},
  @{Name="time";Expression={[int64](Get-Date -UFormat %s)}} |
ConvertTo-Json |
iwr ...

ちなみにホストIDはMackerel Agentが稼働しているホストなら C:\Program Files\Mackerel\mackerel-agent\id にあるので、下記のように変数や環境変数に入れておくと捗ります。

$hostId = Get-Content -Path "C:\Program Files\Mackerel\mackerel-agent\id"
$Env:HOST_ID = Get-Content -Path "C:\Program Files\Mackerel\mackerel-agent\id"

あとはタスクスケジューラにでも登録するなり、Mackerel Agent Pluginとして仕上げるなりするとよさそうです。 またサービスメトリックも同じ要領で投稿できるので、Azureモジュールを利用するAzure Functionsなども考えられます。

利用可能なコマンドレットやパフォーマンスカウンター自体も取得できるので、眺めてみるといいアイディアが閃くかもしれません。

Get-Command -Verb Get
Get-Counter -ListSet *

Mackerel Advent Calendar 2023 8日目は id:ne-sachirou さんです。

[PR] Mackerel Meetup #15 Tokyoを2023年12月19日(火)に開催します

「チームとコミュニティで監視を育てる」をテーマに、監視を育てるスタート地点でもあり、考え方でもある「SRE」の概念やその導入方法、具体的な実装について知ることのできるコンテンツを用意しています。 Mackerelをお使いの方も、これから使い始めようという方も、明日から自分たちの監視やシステムを育てるヒントにしていただけたら幸いです。ぜひMackerelチームメンバーに会いに来てください!

詳細とご応募はこちらから!

mackerelio.connpass.com