This is an automated email from the ASF dual-hosted git repository.
gongchao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hertzbeat.git
The following commit(s) were added to refs/heads/master by this push:
new 348b50c4c [feature] Optimize script protocol and add Windows-script
yml template (#2367)
348b50c4c is described below
commit 348b50c4c6491a06c7c108f89e49b3821cc87965
Author: Zhang Yuxuan <[email protected]>
AuthorDate: Wed Jul 24 23:38:10 2024 +0800
[feature] Optimize script protocol and add Windows-script yml template
(#2367)
Signed-off-by: Zhang Yuxuan <[email protected]>
Co-authored-by: tomsun28 <[email protected]>
---
.../collect/script/ScriptCollectImpl.java | 51 +++-
.../common/entity/job/protocol/ScriptProtocol.java | 5 +
.../src/main/resources/define/app-linux_script.yml | 9 +
.../main/resources/define/app-windows_script.yml | 334 +++++++++++++++++++++
4 files changed, 383 insertions(+), 16 deletions(-)
diff --git
a/collector/src/main/java/org/apache/hertzbeat/collector/collect/script/ScriptCollectImpl.java
b/collector/src/main/java/org/apache/hertzbeat/collector/collect/script/ScriptCollectImpl.java
index 10dbe0096..aa7dc0674 100644
---
a/collector/src/main/java/org/apache/hertzbeat/collector/collect/script/ScriptCollectImpl.java
+++
b/collector/src/main/java/org/apache/hertzbeat/collector/collect/script/ScriptCollectImpl.java
@@ -46,10 +46,13 @@ import org.springframework.util.StringUtils;
public class ScriptCollectImpl extends AbstractCollect {
public static final String WINDOWS_SCRIPT = "windows_script";
public static final String LINUX_SCRIPT = "linux_script";
- private static final String CMD = "cmd.exe";
+ private static final String CMD = "cmd";
private static final String BASH = "bash";
+ private static final String POWERSHELL = "powershell";
private static final String CMD_C = "/c";
private static final String BASH_C = "-c";
+ private static final String POWERSHELL_C = "-Command";
+ private static final String POWERSHELL_FILE = "-File";
private static final String PARSE_TYPE_ONE_ROW = "oneRow";
private static final String PARSE_TYPE_MULTI_ROW = "multiRow";
private static final String PARSE_TYPE_NETCAT = "netcat";
@@ -62,6 +65,7 @@ public class ScriptCollectImpl extends AbstractCollect {
Assert.notNull(scriptProtocol, "Script collect must has Imap params");
Assert.notNull(scriptProtocol.getCharset(), "Script charset is
required");
Assert.notNull(scriptProtocol.getParseType(), "Script parse type is
required");
+ Assert.notNull(scriptProtocol.getScriptTool(), "Script tool is
required");
if (!(StringUtils.hasText(scriptProtocol.getScriptCommand()) ||
StringUtils.hasText(scriptProtocol.getScriptPath()))) {
throw new IllegalArgumentException("At least one script command or
script path is required.");
}
@@ -72,35 +76,50 @@ public class ScriptCollectImpl extends AbstractCollect {
ScriptProtocol scriptProtocol = metrics.getScript();
long startTime = System.currentTimeMillis();
ProcessBuilder processBuilder;
- if (WINDOWS_SCRIPT.equalsIgnoreCase(app)) {
- if (StringUtils.hasText(scriptProtocol.getScriptCommand())) {
- processBuilder = new ProcessBuilder(CMD, CMD_C,
scriptProtocol.getScriptCommand().trim());
- } else {
- processBuilder = new ProcessBuilder(CMD,
scriptProtocol.getScriptPath().trim());
+ // use command
+ if (StringUtils.hasText(scriptProtocol.getScriptCommand())) {
+ switch (scriptProtocol.getScriptTool()) {
+ case BASH -> processBuilder = new ProcessBuilder(BASH, BASH_C,
scriptProtocol.getScriptCommand().trim());
+ case CMD -> processBuilder = new ProcessBuilder(CMD, CMD_C,
scriptProtocol.getScriptCommand().trim());
+ case POWERSHELL -> processBuilder = new
ProcessBuilder("powershell.exe", POWERSHELL_C,
scriptProtocol.getScriptCommand().trim());
+ default -> {
+ builder.setCode(CollectRep.Code.FAIL);
+ builder.setMsg("Not support script tool:" +
scriptProtocol.getScriptTool());
+ return;
+ }
}
-
- } else if (LINUX_SCRIPT.equalsIgnoreCase(app)) {
- if (StringUtils.hasText(scriptProtocol.getScriptCommand())) {
- processBuilder = new ProcessBuilder(BASH, BASH_C,
scriptProtocol.getScriptCommand().trim());
- } else {
- processBuilder = new ProcessBuilder(BASH,
scriptProtocol.getScriptPath().trim());
+ // use command file
+ } else if (StringUtils.hasText((scriptProtocol.getScriptPath()))) {
+ switch (scriptProtocol.getScriptTool()) {
+ case BASH -> processBuilder = new ProcessBuilder(BASH,
scriptProtocol.getScriptPath().trim());
+ case CMD -> processBuilder = new ProcessBuilder(CMD,
scriptProtocol.getScriptPath().trim());
+ case POWERSHELL -> processBuilder = new
ProcessBuilder(POWERSHELL, POWERSHELL_FILE,
scriptProtocol.getScriptPath().trim());
+ default -> {
+ builder.setCode(CollectRep.Code.FAIL);
+ builder.setMsg("Not support script tool:" +
scriptProtocol.getScriptTool());
+ return;
+ }
}
} else {
builder.setCode(CollectRep.Code.FAIL);
- builder.setMsg("Not support OS:" + app);
+ builder.setMsg("At least one script command or script path is
required.");
return;
}
+ // set work directory
String workDirectory = scriptProtocol.getWorkDirectory();
if (StringUtils.hasText(workDirectory)) {
processBuilder.directory(new File(workDirectory));
}
+ // execute command
try {
Process process = processBuilder.start();
BufferedReader reader = new BufferedReader(new
InputStreamReader(process.getInputStream(),
Charset.forName(scriptProtocol.getCharset())));
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
- response.append(line).append("\n");
+ if (StringUtils.hasText(line)) {
+ response.append(line).append("\n");
+ }
}
process.waitFor();
Long responseTime = System.currentTimeMillis() - startTime;
@@ -224,13 +243,13 @@ public class ScriptCollectImpl extends AbstractCollect {
log.error("ssh response data only has header: {}", result);
return;
}
- String[] fields = lines[0].split(" ");
+ String[] fields = lines[0].split("\\s+");
Map<String, Integer> fieldMapping = new HashMap<>(fields.length);
for (int i = 0; i < fields.length; i++) {
fieldMapping.put(fields[i].trim().toLowerCase(), i);
}
for (int i = 1; i < lines.length; i++) {
- String[] values = lines[i].split(" ");
+ String[] values = lines[i].split("\\s+");
CollectRep.ValueRow.Builder valueRowBuilder =
CollectRep.ValueRow.newBuilder();
for (String alias : aliasFields) {
if (CollectorConstants.RESPONSE_TIME.equalsIgnoreCase(alias)) {
diff --git
a/common/src/main/java/org/apache/hertzbeat/common/entity/job/protocol/ScriptProtocol.java
b/common/src/main/java/org/apache/hertzbeat/common/entity/job/protocol/ScriptProtocol.java
index 11079a1b8..1f116b30a 100644
---
a/common/src/main/java/org/apache/hertzbeat/common/entity/job/protocol/ScriptProtocol.java
+++
b/common/src/main/java/org/apache/hertzbeat/common/entity/job/protocol/ScriptProtocol.java
@@ -55,4 +55,9 @@ public class ScriptProtocol {
* Response data parsing mode:oneRow, multiRow
*/
private String parseType;
+
+ /**
+ * Script tool name, exp: bash, cmd, powershell
+ */
+ private String scriptTool;
}
diff --git a/manager/src/main/resources/define/app-linux_script.yml
b/manager/src/main/resources/define/app-linux_script.yml
index 9de6a45e7..b5d2633ed 100644
--- a/manager/src/main/resources/define/app-linux_script.yml
+++ b/manager/src/main/resources/define/app-linux_script.yml
@@ -74,6 +74,8 @@ metrics:
protocol: script
# the config content when protocol is ssh
script:
+ # script tool
+ scriptTool: bash
# OS charset
charset: UTF-8
# script working directory
@@ -139,6 +141,7 @@ metrics:
- usage=100-idle
protocol: script
script:
+ scriptTool: bash
charset: UTF-8
scriptCommand:
|
@@ -202,6 +205,7 @@ metrics:
- usage=(used / total) * 100
protocol: script
script:
+ scriptTool: bash
charset: UTF-8
scriptCommand: free -m | awk 'BEGIN{print "total used free buff_cache
available"} NR==2{print $2,$3,$4,$6,$7}'
parseType: multiRow
@@ -240,6 +244,7 @@ metrics:
en-US: Write Rate
protocol: script
script:
+ scriptTool: bash
charset: UTF-8
scriptCommand: vmstat -D | awk 'NR==1{print $1}';vmstat -D | awk
'NR==2{print $1}';vmstat 1 1 | awk 'NR==3{print $10}';vmstat 1 1 | awk
'NR==3{print $9}';vmstat 1 1 | awk 'NR==3{print $16}'
parseType: oneRow
@@ -273,6 +278,7 @@ metrics:
- transmit_bytes=B->MB
protocol: script
script:
+ scriptTool: bash
charset: UTF-8
scriptCommand: cat /proc/net/dev | tail -n +3 | awk 'BEGIN{ print
"interface_name receive_bytes transmit_bytes"} {print $1,$2,$10}'
parseType: multiRow
@@ -314,6 +320,7 @@ metrics:
en-US: Mounted
protocol: script
script:
+ scriptTool: bash
charset: UTF-8
scriptCommand: df -mP | tail -n +2 | awk 'BEGIN{ print "filesystem used
available usage mounted"} {print $1,$3,$4,$5,$6}'
parseType: multiRow
@@ -349,6 +356,7 @@ metrics:
en-US: Command
protocol: script
script:
+ scriptTool: bash
charset: UTF-8
scriptCommand: ps aux | sort -k3nr | awk 'BEGIN{ print "pid cpu_usage
mem_usage command" } {printf "%s %s %s ", $2, $3, $4; for (i=11; i<=NF; i++) {
printf "%s", $i; if (i < NF) printf " "; } print ""}' | head -n 11
parseType: multiRow
@@ -384,6 +392,7 @@ metrics:
en-US: Command
protocol: script
script:
+ scriptTool: bash
charset: UTF-8
scriptCommand: ps aux | sort -k4nr | awk 'BEGIN{ print "pid cpu_usage
mem_usage command" } {printf "%s %s %s ", $2, $3, $4; for (i=11; i<=NF; i++) {
printf "%s", $i; if (i < NF) printf " "; } print ""}' | head -n 11
parseType: multiRow
diff --git a/manager/src/main/resources/define/app-windows_script.yml
b/manager/src/main/resources/define/app-windows_script.yml
new file mode 100644
index 000000000..a13e9e248
--- /dev/null
+++ b/manager/src/main/resources/define/app-windows_script.yml
@@ -0,0 +1,334 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# The monitoring type category:service-application service monitoring
db-database monitoring custom-custom monitoring os-operating system monitoring
+category: os
+# The monitoring type eg: linux windows tomcat mysql aws...
+app: windows_script
+# The monitoring i18n name
+name:
+ zh-CN: Windows 命令
+ en-US: Windows Script
+# The description and help of this monitoring type
+help:
+ zh-CN: Hertzbeat 使用采集器作为 agent 直接运行 <a class='help_module_content'
href='https://hertzbeat.apache.org/docs/advanced/extend-script'> CMD 或
Powershell 命令 </a> 对 Windows 操作系统的通用性能指标 (系统信息、CPU、内存、磁盘、网卡、文件系统、TOP资源进程等)
进行采集监控。<br>您可以点击“<i>新建 Linux Script</i>”进行添加。或者选择“<i>更多操作</i>”,导入已有配置。
+ en-US: Hertzbeat uses a collector as an agent to directly execute <a
class='help_module_content'
href='https://hertzbeat.apache.org/docs/advanced/extend-script'> CMD or
Powershell commands </a> to collect and monitor general performance metrics of
the Windows operating system (system information, CPU, memory, disk, network
card, file system, TOP resource processes, etc.).<br>You can click “<i>Create
New Linux Script</i>” to add it. Or select “<i>More Actions</i>” to import an
existing [...]
+ zh-TW: Hertzbeat 使用采集器作為 agent 直接運行 <a class='help_module_content'
href='https://hertzbeat.apache.org/docs/advanced/extend-script'> CMD 或
Powershell 命令 </a> 對 Windows 操作系統的通用性能指標 (系統信息、CPU、內存、磁盤、網卡、文件系統、TOP資源進程等)
進行採集監控。<br>您可以點擊“<i>新建 Linux Script</i>”進行添加。或者選擇“<i>更多操作</i>”,導入已有配置。
+helpLink:
+ zh-CN: https://hertzbeat.apache.org/zh-cn/docs/help/script
+ en-US: https://hertzbeat.apache.org/docs/help/script
+# Input params define for monitoring(render web ui by the definition)
+params:
+ # field-param field key
+ - field: host
+ # name-param field display i18n name
+ name:
+ zh-CN: 目标Host
+ en-US: Target Host
+ # type-param field type(most mapping the html input type)
+ type: host
+ # required-true or false
+ required: true
+# collect metrics config list
+metrics:
+ # metrics - basic, inner monitoring metrics (responseTime - response time)
+ - name: basic
+ i18n:
+ zh-CN: 系统基本信息
+ en-US: Basic Info
+ # metrics scheduling priority(0->127)->(high->low), metrics with the same
priority will be scheduled in parallel
+ # priority 0's metrics is availability metrics, it will be scheduled
first, only availability metrics collect success will the scheduling continue
+ priority: 0
+ # collect metrics content
+ fields:
+ # field-metric name, type-metric type(0-number,1-string), unit-metric
unit('%','ms','MB'), label-whether it is a metrics label field
+ - field: hostname
+ type: 1
+ label: true
+ i18n:
+ zh-CN: 主机名称
+ en-US: Host Name
+ - field: version
+ type: 1
+ i18n:
+ zh-CN: 操作系统版本
+ en-US: System Version
+ # the protocol used for monitoring, eg: sql, ssh, http, telnet, wmi, snmp,
sdk
+ protocol: script
+ # the config content when protocol is ssh
+ script:
+ # script tool
+ scriptTool: cmd
+ # OS charset
+ charset: GBK
+ # script working directory
+ workDirectory: "C:"
+ # collect script
+ scriptCommand:
+ |
+ @echo %COMPUTERNAME% & for /f "tokens=4 delims=[] " %i in ('ver') do
@echo %i
+ # response data parse type: oneRow, multiRow
+ parseType: oneRow
+
+ - name: cpu
+ i18n:
+ zh-CN: CPU 信息
+ en-US: CPU Info
+ priority: 1
+ fields:
+ - field: info
+ type: 1
+ i18n:
+ zh-CN: 型号
+ en-US: Info
+ - field: cores
+ type: 1
+ i18n:
+ zh-CN: 核数
+ en-US: Cores
+ - field: load
+ type: 1
+ unit: '%'
+ i18n:
+ zh-CN: 负载
+ en-US: Load
+ - field: interrupt
+ type: 1
+ i18n:
+ zh-CN: 中断数
+ en-US: Interrupt
+ - field: context_switch
+ type: 1
+ i18n:
+ zh-CN: 上下文切换
+ en-US: Context Switch
+ - field: usage
+ type: 1
+ unit: '%'
+ i18n:
+ zh-CN: 使用率
+ en-US: Usage
+ protocol: script
+ script:
+ scriptTool: cmd
+ charset: GBK
+ scriptCommand:
+ |
+ for /f "tokens=2 delims==" %i in ('wmic cpu get Name /value ^| find
"Name"') do @echo %i&&for /f "tokens=2 delims==" %i in ('wmic cpu get
NumberOfLogicalProcessors /value ^| find "NumberOfLogicalProcessors"') do @echo
%i&&for /f "tokens=2 delims==" %i in ('wmic cpu get loadpercentage /value') do
@echo %i&&for /f "skip=2 tokens=2 delims=," %a in ('typeperf "\Processor
Information(_Total)\Interrupts/sec" -sc 1') do @echo %a && for /f "skip=2
tokens=2 delims=," %a in ('typeperf "\Sy [...]
+ parseType: oneRow
+
+ - name: memory
+ i18n:
+ zh-CN: 内存信息
+ en-US: Memory Info
+ priority: 1
+ fields:
+ - field: totalPhysical
+ type: 0
+ unit: Mb
+ i18n:
+ zh-CN: 总物理内存容量
+ en-US: Total Physical Memory
+ - field: freePhysical
+ type: 0
+ unit: Mb
+ i18n:
+ zh-CN: 空闲物理内存容量
+ en-US: Free Physical Memory
+ - field: totalVirtual
+ type: 0
+ unit: Mb
+ i18n:
+ zh-CN: 总虚拟内存容量
+ en-US: Total Virtual Memory
+ - field: freeVirtual
+ type: 0
+ unit: Mb
+ i18n:
+ zh-CN: 空闲虚拟内存容量
+ en-US: Free Virtual Memory
+ units:
+ - totalPhysical=B->MB
+ - freePhysical=KB->MB
+ - totalVirtual=KB->MB
+ - freeVirtual=KB->MB
+ protocol: script
+ script:
+ scriptTool: cmd
+ charset: GBK
+ scriptCommand:
+ |
+ for /f "tokens=2 delims==" %i in ('wmic computerSystem get
TotalPhysicalMemory /value ^| find "TotalPhysicalMemory"') do @echo %i&&for /f
"tokens=2 delims==" %i in ('wmic os get FreePhysicalMemory /value ^| find
"FreePhysicalMemory"') do @echo %i&&for /f "tokens=2 delims==" %i in ('wmic os
get TotalVirtualMemorySize /value ^| find "TotalVirtualMemorySize"') do @echo
%i&&for /f "tokens=2 delims==" %i in ('wmic os get FreeVirtualMemory /value ^|
find "FreeVirtualMemory"') do @echo %i
+ parseType: oneRow
+
+ - name: disk
+ i18n:
+ zh-CN: 磁盘信息
+ en-US: Disk Info
+ priority: 1
+ fields:
+ - field: Model
+ type: 1
+ i18n:
+ zh-CN: 磁盘型号
+ en-US: Disk Type
+ - field: Size
+ type: 0
+ unit: Mb
+ i18n:
+ zh-CN: 磁盘大小
+ en-US: Disk Size
+ - field: BytesPerSector
+ type: 0
+ i18n:
+ zh-CN: 每个扇区的字节数
+ en-US: Bytes Per Sector
+ protocol: script
+ script:
+ scriptTool: powershell
+ charset: GBK
+ scriptCommand:
+ |
+ Write-Host "Model Size BytesPerSector";
+ Get-WmiObject -Class Win32_DiskDrive | ForEach-Object {
+ $model = $_.Model -replace ' ', '_'
+ $size = [math]::round($_.Size / 1MB, 0)
+ $bytesPerSector = $_.BytesPerSector
+ Write-Host "$model $size $bytesPerSector"
+ }
+ parseType: multiRow
+
+ - name: disk_free
+ i18n:
+ zh-CN: 文件系统
+ en-US: Disk Free
+ priority: 1
+ fields:
+ - field: Caption
+ type: 1
+ i18n:
+ zh-CN: 盘符
+ en-US: Caption
+ - field: FreeSpace
+ type: 0
+ unit: Mb
+ i18n:
+ zh-CN: 可用量
+ en-US: FreeSpace
+ - field: Size
+ type: 0
+ unit: Mb
+ i18n:
+ zh-CN: 总量
+ en-US: Size
+ units:
+ - FreeSpace=B->MB
+ - Size=B->MB
+ protocol: script
+ script:
+ scriptTool: cmd
+ charset: GBK
+ scriptCommand:
+ |
+ wmic logicaldisk get size,freespace,caption
+ parseType: multiRow
+
+ - name: top_cpu_process
+ i18n:
+ zh-CN: Top10 CPU 进程
+ en-US: Top10 CPU Process
+ priority: 1
+ fields:
+ - field: name
+ type: 1
+ i18n:
+ zh-CN: 进程名
+ en-US: Name
+ - field: id
+ type: 1
+ i18n:
+ zh-CN: 进程 ID
+ en-US: PID
+ - field: cpu
+ type: 0
+ unit: 's'
+ i18n:
+ zh-CN: CPU 使用时间
+ en-US: CPU Usage Time
+ - field: ws
+ type: 0
+ unit: Mb
+ i18n:
+ zh-CN: 内存占用量
+ en-US: Memory Usage
+ protocol: script
+ script:
+ scriptTool: powershell
+ charset: GBK
+ scriptCommand:
+ |
+ Write-Host "name id cpu ws";
+ Get-Process | Sort-Object -Property CPU -Descending | Select-Object
-First 10 | ForEach-Object {
+ $name = $_.Name -replace ' ', '_'
+ $id = $_.Id
+ $cpu = [math]::round($_.CPU, 0)
+ $ws = [math]::round($_.WS / 1MB, 0)
+ Write-Host "$name $id $cpu $ws"
+ }
+ parseType: multiRow
+
+ - name: top_mem_process
+ i18n:
+ zh-CN: Top10 内存进程
+ en-US: Top10 Memory Process
+ priority: 1
+ fields:
+ - field: name
+ type: 1
+ i18n:
+ zh-CN: 进程名称
+ en-US: Process Name
+ - field: id
+ type: 1
+ i18n:
+ zh-CN: 进程 ID
+ en-US: PID
+ - field: ws
+ type: 0
+ unit: Mb
+ i18n:
+ zh-CN: 内存占用量
+ en-US: Memory Usage
+ - field: cpu
+ type: 0
+ unit: s
+ i18n:
+ zh-CN: CPU 占用时间
+ en-US: CPU Usage Time
+ protocol: script
+ script:
+ scriptTool: powershell
+ charset: GBK
+ scriptCommand:
+ |
+ Write-Host "name id ws cpu";
+ Get-Process | Sort-Object -Property WS -Descending | Select-Object
-First 10 | ForEach-Object {
+ $name = $_.Name -replace ' ', '_'
+ $id = $_.Id
+ $ws = [math]::round($_.WS / 1MB, 0)
+ $cpu = [math]::round($_.CPU, 0)
+ Write-Host "$name $id $ws $cpu"
+ }
+ parseType: multiRow
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]