我有一个 JSON 结果,如果 JSON 字符串中的一个或多个值超出阈值,我想对其进行检查并发送警报。
这个 bash 命令:
for sat in `docker exec -i storagenode wget -qO - localhost:14002/api/sno | jq .satellites[].id -r`; do docker exec -i storagenode wget -qO - localhost:14002/api/sno/satellite/$sat | jq .id,.audits; done
提供以下内容(摘录):
"12tRQrMTWUWwzwGh18i7Fqs67kmdhH9t6aToeiwbo5mfS2rUmo"
{
"auditScore": 1,
"suspensionScore": 1,
"onlineScore": 0.9974358974358974,
"satelliteName": "us2.storj.io:7777"
}
"1wFTAgs9DP5RSnCqKV1eLf6N9wtk4EAtmN5DpSxcs8EjT69tGE"
{
"auditScore": 1,
"suspensionScore": 1,
"onlineScore": 0.9989041005632043,
"satelliteName": "saltlake.tardigrade.io:7777"
}
现在我想查看结果,例如,如果 onlineScore 降至 0.9 以下(或 sailingScore 或auditScore 低于 1.0),我想创建一个文本警报,其中还包括卫星名称。示例:auditScore below threshold: 0.98 for us2.storj.io
我想我可以从以下开始(从使用 jq 将 JSON 数组转换为 bash 变量),但我不知道如何循环结果以及如何命名和验证字段:
jq -r '.[] | to_entries | .[] | .key + "=" + (.value | @sh)'
更新#1
docker exec -i storagenode wget -qO - localhost:14002/api/sno
提供:
{"nodeID":"1veqEG5xuBNkt...","wallet":"12345","walletFeatures":["zksync"],"satellites":[{"id":"12tRQrMTWUWwzwGh18i7Fqs67kmdhH9t6aToeiwbo5mfS2rUmo","url":"us2.storj.io:7777","disqualified":null,"suspended":null,"currentStorageUsed":4592556672},{"id":"1wFTAgs9DP5RSnCqKV1eLf6N9wtk4EAtmN5DpSxcs8EjT69tGE","url":"saltlake.tardigrade.io:7777","disqualified":null,"suspended":null,"currentStorageUsed":513269323264},{"id":"121RTSDpyNZVcEU84Ticf2L1ntiuUimbWgfATz21tuvgk3vzoA6","url":"ap1.storj.io:7777","disqualified":null,"suspended":null,"currentStorageUsed":70956116864},{"id":"12EayRS2V1kEsWESU9QMRseFhdxYxKicsiFmxrsLZHeLUtdps3S","url":"us1.storj.io:7777","disqualified":null,"suspended":null,"currentStorageUsed":322340591104},{"id":"12L9ZFwhzVpuEKMUNUqkaTLGzwY9G24tbiigLiXpmZWKwmcNDDs","url":"eu1.storj.io:7777","disqualified":null,"suspended":null,"currentStorageUsed":148740125312},{"id":"12rfG3sh9NCWiX3ivPjq2HtdLmbqCrvHVEzJubnzFzosMuawymB","url":"europe-north-1.tardigrade.io:7777","disqualified":null,"suspended":null,"currentStorageUsed":100681406976}],"diskSpace":{"used":1162257094528,"available":9500000000000,"trash":43196690332,"overused":0},"bandwidth":{"used":31670206976,"available":0},"lastPinged":"2022-01-02T07:55:51.886776586Z","version":"1.45.3","allowedVersion":"1.24.0","upToDate":true,"startedAt":"2021-12-31T00:00:32.209840775Z"}
和这个:
docker exec -i storagenode wget -qO - localhost:14002/api/sno/satellite/1wFTAgs9DP5RSnCqKV1eLf6N9wtk4EAtmN5DpSxcs8EjT69tGE
提供:
{"id":"1wFTAgs9DP5RSnCqKV1eLf6N9wtk4EAtmN5DpSxcs8EjT69tGE","storageDaily":[{"atRestTotal":11726579066524.266,"intervalStart":"2022-01-01T00:00:00Z"}],"bandwidthDaily":[{"egress":{"repair":390576640,"audit":7424,"usage":2373615872},"ingress":{"repair":2745100032,"usage":26744320},"delete":0,"intervalStart":"2022-01-01T00:00:00Z"},{"egress":{"repair":143168256,"audit":3584,"usage":786989568},"ingress":{"repair":1034401280,"usage":8107264},"delete":0,"intervalStart":"2022-01-02T00:00:00Z"}],"storageSummary":11726579066524.266,"bandwidthSummary":7508714240,"egressSummary":3694361344,"ingressSummary":3814352896,"currentStorageUsed":513269323264,"audits":{"auditScore":1,"suspensionScore":1,"onlineScore":0.9989041005632043,"satelliteName":"saltlake.tardigrade.io:7777"},"auditHistory":{"score":0.9989041005632043,"windows":[{"windowStart":"2021-12-03T00:00:00Z","totalCount":36,"onlineCount":36},{"windowStart":"2021-12-03T12:00:00Z","totalCount":30,"onlineCount":30},{"windowStart":"2021-12-04T00:00:00Z","totalCount":43,"onlineCount":42},{"windowStart":"2021-12-04T12:00:00Z","totalCount":68,"onlineCount":68},{"windowStart":"2021-12-05T00:00:00Z","totalCount":53,"onlineCount":53},{"windowStart":"2021-12-05T12:00:00Z","totalCount":36,"onlineCount":36},{"windowStart":"2021-12-06T00:00:00Z","totalCount":33,"onlineCount":33},{"windowStart":"2021-12-06T12:00:00Z","totalCount":53,"onlineCount":53},{"windowStart":"2021-12-07T00:00:00Z","totalCount":27,"onlineCount":27},{"windowStart":"2021-12-07T12:00:00Z","totalCount":65,"onlineCount":65},{"windowStart":"2021-12-08T00:00:00Z","totalCount":30,"onlineCount":30},{"windowStart":"2021-12-08T12:00:00Z","totalCount":27,"onlineCount":27},{"windowStart":"2021-12-09T00:00:00Z","totalCount":46,"onlineCount":46},{"windowStart":"2021-12-09T12:00:00Z","totalCount":48,"onlineCount":48},{"windowStart":"2021-12-10T00:00:00Z","totalCount":49,"onlineCount":49},{"windowStart":"2021-12-10T12:00:00Z","totalCount":67,"onlineCount":67},{"windowStart":"2021-12-11T00:00:00Z","totalCount":71,"onlineCount":71},{"windowStart":"2021-12-11T12:00:00Z","totalCount":52,"onlineCount":52},{"windowStart":"2021-12-12T00:00:00Z","totalCount":59,"onlineCount":59},{"windowStart":"2021-12-12T12:00:00Z","totalCount":77,"onlineCount":77},{"windowStart":"2021-12-13T00:00:00Z","totalCount":79,"onlineCount":79},{"windowStart":"2021-12-13T12:00:00Z","totalCount":79,"onlineCount":79},{"windowStart":"2021-12-14T00:00:00Z","totalCount":65,"onlineCount":65},{"windowStart":"2021-12-14T12:00:00Z","totalCount":59,"onlineCount":59},{"windowStart":"2021-12-15T00:00:00Z","totalCount":87,"onlineCount":87},{"windowStart":"2021-12-15T12:00:00Z","totalCount":82,"onlineCount":81},{"windowStart":"2021-12-16T00:00:00Z","totalCount":96,"onlineCount":96},{"windowStart":"2021-12-16T12:00:00Z","totalCount":66,"onlineCount":64},{"windowStart":"2021-12-17T00:00:00Z","totalCount":36,"onlineCount":36},{"windowStart":"2021-12-17T12:00:00Z","totalCount":48,"onlineCount":48},{"windowStart":"2021-12-18T00:00:00Z","totalCount":37,"onlineCount":37},{"windowStart":"2021-12-18T12:00:00Z","totalCount":60,"onlineCount":60},{"windowStart":"2021-12-19T00:00:00Z","totalCount":69,"onlineCount":69},{"windowStart":"2021-12-19T12:00:00Z","totalCount":32,"onlineCount":32},{"windowStart":"2021-12-20T00:00:00Z","totalCount":53,"onlineCount":53},{"windowStart":"2021-12-20T12:00:00Z","totalCount":37,"onlineCount":37},{"windowStart":"2021-12-21T00:00:00Z","totalCount":80,"onlineCount":80},{"windowStart":"2021-12-21T12:00:00Z","totalCount":57,"onlineCount":57},{"windowStart":"2021-12-22T00:00:00Z","totalCount":46,"onlineCount":46},{"windowStart":"2021-12-22T12:00:00Z","totalCount":33,"onlineCount":33},{"windowStart":"2021-12-23T00:00:00Z","totalCount":42,"onlineCount":42},{"windowStart":"2021-12-23T12:00:00Z","totalCount":73,"onlineCount":73},{"windowStart":"2021-12-24T00:00:00Z","totalCount":35,"onlineCount":35},{"windowStart":"2021-12-24T12:00:00Z","totalCount":44,"onlineCount":44},{"windowStart":"2021-12-25T00:00:00Z","totalCount":81,"onlineCount":81},{"windowStart":"2021-12-25T12:00:00Z","totalCount":43,"onlineCount":43},{"windowStart":"2021-12-26T00:00:00Z","totalCount":62,"onlineCount":62},{"windowStart":"2021-12-26T12:00:00Z","totalCount":79,"onlineCount":79},{"windowStart":"2021-12-27T00:00:00Z","totalCount":70,"onlineCount":70},{"windowStart":"2021-12-27T12:00:00Z","totalCount":90,"onlineCount":90},{"windowStart":"2021-12-28T00:00:00Z","totalCount":65,"onlineCount":65},{"windowStart":"2021-12-28T12:00:00Z","totalCount":77,"onlineCount":77},{"windowStart":"2021-12-29T00:00:00Z","totalCount":83,"onlineCount":83},{"windowStart":"2021-12-29T12:00:00Z","totalCount":99,"onlineCount":99},{"windowStart":"2021-12-30T00:00:00Z","totalCount":74,"onlineCount":74},{"windowStart":"2021-12-30T12:00:00Z","totalCount":84,"onlineCount":84},{"windowStart":"2021-12-31T00:00:00Z","totalCount":70,"onlineCount":70},{"windowStart":"2021-12-31T12:00:00Z","totalCount":93,"onlineCount":93},{"windowStart":"2022-01-01T00:00:00Z","totalCount":120,"onlineCount":120},{"windowStart":"2022-01-01T12:00:00Z","totalCount":112,"onlineCount":112},{"windowStart":"2022-01-02T00:00:00Z","totalCount":46,"onlineCount":46}]},"priceModel":{"EgressBandwidth":2000,"RepairBandwidth":1000,"AuditBandwidth":1000,"DiskSpace":150},"nodeJoinedAt":"2021-05-11T20:11:14.910165Z"}
抱歉,不知道如何以更好的方式更好地格式化这里巨大的 json 内容。
更新#2
有一个结果http://localhost:14002/api/sno/satellites
,我以前不知道。结果是:
{
...
"storageSummary": 6.8624392E13,
...
"audits": [
{
"auditScore": 1,
"suspensionScore": 1,
"onlineScore": 0.99743587,
"satelliteName": "us2.storj.io:7777"
},
{
"auditScore": 1,
"suspensionScore": 1,
"onlineScore": 0.9992917,
"satelliteName": "saltlake.tardigrade.io:7777"
},
...
{
"auditScore": 1,
"suspensionScore": 1,
"onlineScore": 0.99930555,
"satelliteName": "ap1.storj.io:7777"
}
]
}
答案1
通常,避免循环命令替换的结果是一个好主意。这是不优雅的,因为替换中的命令必须在循环开始运行之前完成执行,它的效率很低,因为替换中命令的完整结果必须存储在内存中,而且很容易出错,因为必须允许 shell 分割命令的输出包含空格,并使结果单词服从文件名通配。
最好read
在while
循环中使用:
#!/bin/sh
curl -s 'localhost:14002/api/sno' |
jq -r '.satellites[].id' |
while IFS= read -r id; do
curl -s 'localhost:14002/api/sno/satellite/'"$id"
done |
jq -r \
--argjson auditScore 1 \
--argjson suspensionScore 1 \
--argjson onlineScore 0.9 \
'.audits as $a | $a.satelliteName as $name |
reduce ($ARGS.named|keys[]) as $key (
[];
if $a[$key] < $ARGS.named[$key] then (
. + ["\($key) below threshold: \($a[$key]) for \($name)"]
) else . end
) | .[]'
此脚本假设您可以联系 REST 端点localhost:14002
(例如,Docker 容器可能会公开该端口)。如果您需要使用docker exec
命令访问 API,请将普通调用替换为curl
,例如
docker exec -i curl -s 'localhost:14002/api/sno'
对于更新的问题,使用api/sno/satellites
端点:
#!/bin/sh
curl -s 'localhost:14002/api/sno/satellites' |
jq -r \
--argjson auditScore 1 \
--argjson suspensionScore 1 \
--argjson onlineScore 0.9 \
'.audits[] as $a | $a.satelliteName as $name |
reduce ($ARGS.named|keys[]) as $key (
[];
if $a[$key] < $ARGS.named[$key] then (
. + ["\($key) below threshold: \($a[$key]) for \($name)"]
) else . end
) | .[]'
除了对表达式进行细微调整之外jq
,这本质上与上面的代码相同,但绕过了第一次curl
调用以获取所有 ID 和循环。
答案2
我找到了一个可能的答案堆栈溢出:
for sat in `docker exec -i storagenode wget -qO - localhost:14002/api/sno | jq .satellites[].id -r`
do
docker exec -i storagenode wget -qO - localhost:14002/api/sno/satellite/$sat \
| jq --raw-output \
--argjson auditThreshold 1 \
--argjson suspensionThreshold 1 \
--argjson onlineThreshold 1 \
'.audits
| .satelliteName as $name
| (
[{auditScore}, $auditThreshold],
[{suspensionScore}, $suspensionThreshold],
[{onlineScore}, $onlineThreshold]
)
| select(.[0][] < .[1])
| "\(.[0] | keys[]) (\(.[0][])) below threshold (\(.[1])) for \($name)"
'
done