217 lines
10 KiB
Markdown
217 lines
10 KiB
Markdown
# Glance Python 远程服务器监控 Agent
|
||
|
||
## 项目简介
|
||
本项目为 Glance Dashboard 提供远程服务器监控数据采集,使用 Python3 + FastAPI 实现,兼容 Glance `server-stats` 组件前端展示。支持 Docker 部署,适合多服务器统一监控。
|
||
|
||
## 功能特性
|
||
- 采集主机名、平台、启动时间、CPU 负载/温度、内存、磁盘等信息
|
||
- 提供 `/api/sysinfo/all` HTTP API,返回 Glance 兼容 JSON
|
||
- 支持 Docker 镜像和 docker-compose 一键部署
|
||
- 可多实例部署,适配多服务器场景
|
||
- **主机名自动识别**:容器内自动优先读取宿主机 `/etc/hostname`,无需手动配置
|
||
|
||
## API 说明
|
||
- 路径:`/api/sysinfo/all`
|
||
- 方法:GET
|
||
- 返回:
|
||
```json
|
||
{
|
||
"Hostname": "server1",
|
||
"Platform": "Linux-5.15.0-1051-azure-x86_64-with-glibc2.29",
|
||
"BootTime": 1710000000,
|
||
"HostInfoIsAvailable": true,
|
||
"CPU": {
|
||
"Load1Percent": 12.5,
|
||
"Load15Percent": 8.2,
|
||
"TemperatureC": 45.0,
|
||
"LoadIsAvailable": true,
|
||
"TemperatureIsAvailable": true
|
||
},
|
||
"Memory": {
|
||
"IsAvailable": true,
|
||
"UsedPercent": 55.3,
|
||
"UsedMB": 2048,
|
||
"TotalMB": 4096,
|
||
"SwapIsAvailable": true,
|
||
"SwapUsedMB": 256,
|
||
"SwapTotalMB": 1024,
|
||
"SwapUsedPercent": 25.0
|
||
},
|
||
"Mountpoints": [
|
||
{
|
||
"Name": "/dev/sda1",
|
||
"Path": "/",
|
||
"UsedMB": 10240,
|
||
"TotalMB": 20480,
|
||
"UsedPercent": 50.0
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
## Glance 集成方法
|
||
|
||
1. 将 `agent/custom-api-example.yaml` 内容合并到 Glance 的主配置文件(如 `glance.yml`)对应 widgets 区域。
|
||
2. 每台服务器部署一个 agent,配置对应的 API 地址。
|
||
3. 前端展示效果与本地 server-stats 一致。
|
||
|
||
### custom-api 配置示例
|
||
```yaml
|
||
- type: custom-api
|
||
title: 远程服务器A
|
||
url: http://192.168.1.200:8000/api/sysinfo/all ## 请修改为实际的IP地址
|
||
cache: 15s
|
||
template: |
|
||
<div class="server">
|
||
<div class="server-info">
|
||
<div class="server-details">
|
||
<div class="server-name color-highlight size-h3">
|
||
{{ .JSON.String "Hostname" }}
|
||
</div>
|
||
<div>
|
||
{{ if .JSON.Bool "HostInfoIsAvailable" }}
|
||
<span {{ .JSON.Int "BootTime" | printf "%d" | parseTime "unix" | toRelativeTime }}></span> uptime
|
||
{{ else }}unknown uptime{{ end }}
|
||
</div>
|
||
</div>
|
||
<div class="shrink-0" data-popover-type="html" data-popover-margin="0.2rem" data-popover-max-width="400px">
|
||
<div data-popover-html>
|
||
<div class="size-h5 text-compact">PLATFORM</div>
|
||
<div class="color-highlight">
|
||
{{ if .JSON.Bool "HostInfoIsAvailable" }}
|
||
{{ .JSON.String "Platform" }}
|
||
{{ else }}Unknown{{ end }}
|
||
</div>
|
||
</div>
|
||
<!-- 服务器logo -->
|
||
<svg class="server-icon" stroke="var(--color-positive)" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5">
|
||
<path stroke-linecap="round" stroke-linejoin="round" d="M21.75 17.25v-.228a4.5 4.5 0 0 0-.12-1.03l-2.268-9.64a3.375 3.375 0 0 0-3.285-2.602H7.923a3.375 3.375 0 0 0-3.285 2.602l-2.268 9.64a4.5 4.5 0 0 0-.12 1.03v.228m19.5 0a3 3 0 0 1-3 3H5.25a3 3 0 0 1-3-3m19.5 0a3 3 0 0 0-3-3H5.25a3 3 0 0 0-3 3m16.5 0h.008v.008h-.008v-.008Zm-3 0h.008v.008h-.008v-.008Z" />
|
||
</svg>
|
||
</div>
|
||
</div>
|
||
<div class="server-stats">
|
||
<!-- CPU -->
|
||
<div class="flex-1{{ if not (.JSON.Bool "CPU.LoadIsAvailable") }} server-stat-unavailable{{ end }}">
|
||
<div class="flex items-end size-h5">
|
||
<div>CPU</div>
|
||
{{ if and (.JSON.Bool "CPU.TemperatureIsAvailable") (ge (.JSON.Float "CPU.TemperatureC") 80.0) }}
|
||
<svg class="server-spicy-cpu-icon" fill="var(--color-negative)" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" >
|
||
<path fill-rule="evenodd" d="M8.074.945A4.993 4.993 0 0 0 6 5v.032c.004.6.114 1.176.311 1.709.16.428-.204.91-.61.7a5.023 5.023 0 0 1-1.868-1.677c-.202-.304-.648-.363-.848-.058a6 6 0 1 0 8.017-1.901l-.004-.007a4.98 4.98 0 0 1-2.18-2.574c-.116-.31-.477-.472-.744-.28Zm.78 6.178a3.001 3.001 0 1 1-3.473 4.341c-.205-.365.215-.694.62-.59a4.008 4.008 0 0 0 1.873.03c.288-.065.413-.386.321-.666A3.997 3.997 0 0 1 8 8.999c0-.585.126-1.14.351-1.641a.42.42 0 0 1 .503-.235Z" clip-rule="evenodd" />
|
||
</svg>
|
||
{{ end }}
|
||
<div class="color-highlight margin-left-auto text-very-compact">
|
||
{{ if .JSON.Bool "CPU.LoadIsAvailable" }}
|
||
{{ .JSON.Float "CPU.Load1Percent" }} <span class="color-base">%</span>
|
||
{{ else }}n/a{{ end }}
|
||
</div>
|
||
</div>
|
||
<div data-popover-type="html">
|
||
<div data-popover-html>
|
||
<div class="flex">
|
||
<div class="size-h5">1M AVG</div>
|
||
<div class="value-separator"></div>
|
||
<div class="color-highlight text-very-compact">{{ .JSON.Float "CPU.Load1Percent" }} <span class="color-base size-h5">%</span></div>
|
||
</div>
|
||
<div class="flex margin-top-3">
|
||
<div class="size-h5">15M AVG</div>
|
||
<div class="value-separator"></div>
|
||
<div class="color-highlight text-very-compact">{{ .JSON.Float "CPU.Load15Percent" }} <span class="color-base size-h5">%</span></div>
|
||
</div>
|
||
{{ if .JSON.Bool "CPU.TemperatureIsAvailable" }}
|
||
<div class="flex margin-top-3">
|
||
<div class="size-h5">TEMP C</div>
|
||
<div class="value-separator"></div>
|
||
<div class="color-highlight text-very-compact">{{ .JSON.Float "CPU.TemperatureC" }} <span class="color-base size-h5">°</span></div>
|
||
</div>
|
||
{{ end }}
|
||
</div>
|
||
<div class="progress-bar progress-bar-combined">
|
||
{{ if .JSON.Bool "CPU.LoadIsAvailable" }}
|
||
<div class="progress-value{{ if ge (.JSON.Float "CPU.Load1Percent") 85.0 }} progress-value-notice{{ end }}" style="--percent: {{ .JSON.Float "CPU.Load1Percent" }}"></div>
|
||
<div class="progress-value{{ if ge (.JSON.Float "CPU.Load15Percent") 85.0 }} progress-value-notice{{ end }}" style="--percent: {{ .JSON.Float "CPU.Load15Percent" }}"></div>
|
||
{{ end }}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<!-- RAM -->
|
||
<div class="flex-1{{ if not (.JSON.Bool "Memory.IsAvailable") }} server-stat-unavailable{{ end }}">
|
||
<div class="flex justify-between items-end size-h5">
|
||
<div>RAM</div>
|
||
<div class="color-highlight text-very-compact">
|
||
{{ if .JSON.Bool "Memory.IsAvailable" }}
|
||
{{ .JSON.Float "Memory.UsedPercent" }} <span class="color-base">%</span>
|
||
{{ else }}n/a{{ end }}
|
||
</div>
|
||
</div>
|
||
<div data-popover-type="html">
|
||
<div data-popover-html>
|
||
<div class="flex">
|
||
<div class="size-h5">RAM</div>
|
||
<div class="value-separator"></div>
|
||
<div class="color-highlight text-very-compact">
|
||
{{ .JSON.Float "Memory.UsedGB" }}GB <span class="color-base size-h5">/</span> {{ .JSON.Float "Memory.TotalGB" }}GB
|
||
</div>
|
||
</div>
|
||
{{ if .JSON.Bool "Memory.SwapIsAvailable" }}
|
||
<div class="flex margin-top-3">
|
||
<div class="size-h5">SWAP</div>
|
||
<div class="value-separator"></div>
|
||
<div class="color-highlight text-very-compact">
|
||
{{ .JSON.Float "Memory.SwapUsedGB" }}GB <span class="color-base size-h5">/</span> {{ .JSON.Float "Memory.SwapTotalGB" }}GB
|
||
</div>
|
||
</div>
|
||
{{ end }}
|
||
</div>
|
||
<div class="progress-bar progress-bar-combined">
|
||
{{ if .JSON.Bool "Memory.IsAvailable" }}
|
||
<div class="progress-value{{ if ge (.JSON.Float "Memory.UsedPercent") 85.0 }} progress-value-notice{{ end }}" style="--percent: {{ .JSON.Float "Memory.UsedPercent" }}"></div>
|
||
{{ if .JSON.Bool "Memory.SwapIsAvailable" }}
|
||
<div class="progress-value{{ if ge (.JSON.Float "Memory.SwapUsedPercent") 85.0 }} progress-value-notice{{ end }}" style="--percent: {{ .JSON.Float "Memory.SwapUsedPercent" }}"></div>
|
||
{{ end }}
|
||
{{ end }}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<!-- DISK -->
|
||
<div class="flex-1{{ if not ((.JSON.Array "Mountpoints" | len)) }} server-stat-unavailable{{ end }}">
|
||
<div class="flex justify-between items-end size-h5">
|
||
<div>DISK</div>
|
||
<div class="color-highlight text-very-compact">
|
||
{{ if gt (.JSON.Array "Mountpoints" | len) 0 }}
|
||
{{ (index (.JSON.Array "Mountpoints") 0).Float "UsedPercent" }} <span class="color-base">%</span>
|
||
{{ else }}n/a{{ end }}
|
||
</div>
|
||
</div>
|
||
<div data-popover-type="html">
|
||
<div data-popover-html>
|
||
<ul class="list list-gap-2">
|
||
{{ range .JSON.Array "Mountpoints" }}
|
||
<li class="flex">
|
||
<div class="size-h5">{{ if .String "Name" }}{{ .String "Name" }}{{ else }}{{ .String "Path" }}{{ end }}</div>
|
||
<div class="value-separator"></div>
|
||
<div class="color-highlight text-very-compact">
|
||
{{ .Float "UsedGB" }}GB <span class="color-base size-h5">/</span> {{ .Float "TotalGB" }}GB
|
||
</div>
|
||
</li>
|
||
{{ end }}
|
||
</ul>
|
||
</div>
|
||
<div class="progress-bar progress-bar-combined">
|
||
{{ if gt (.JSON.Array "Mountpoints" | len) 0 }}
|
||
<div class="progress-value{{ if ge ((index (.JSON.Array "Mountpoints") 0).Float "UsedPercent") 85.0 }} progress-value-notice{{ end }}" style="--percent: {{ (index (.JSON.Array "Mountpoints") 0).Float "UsedPercent" }}"></div>
|
||
{{ if gt (.JSON.Array "Mountpoints" | len) 1 }}
|
||
<div class="progress-value{{ if ge ((index (.JSON.Array "Mountpoints") 1).Float "UsedPercent") 85.0 }} progress-value-notice{{ end }}" style="--percent: {{ (index (.JSON.Array "Mountpoints") 1).Float "UsedPercent" }}"></div>
|
||
{{ end }}
|
||
{{ end }}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
```
|
||
|
||
## 参考
|
||
- [Glance-Monitor](https://github.com/arch3rPro/Glance-Monitor)
|
||
- [Document文档](https://github.com/arch3rPro/Glance-Monitor/blob/main/server-status-agent/README.md)
|