Compare commits

...

9 Commits

Author SHA1 Message Date
henrygd
0fc4a6daed update install-agent.sh to prefer glibc binary on linux glibc systems 2026-01-12 19:13:14 -05:00
henrygd
af0c1d3af7 release 0.18.2 2026-01-12 18:26:30 -05:00
henrygd
9ad3cd0ab9 fix: GPU ID collision between Intel and NVIDIA collectors (#1522)
- Prefix Intel GPU ID as i0 to avoid NVML/NVIDIA index IDs like 0
- Update frontend GPU engines chart to select a GPU by id instead of
assuming g[0]
- Adjust tests to use the new Intel GPU id
2026-01-12 17:27:35 -05:00
crimist
00def272b0 site: only hide GPU engine graph if entire usage is 0% (#1624) 2026-01-12 17:16:05 -05:00
henrygd
383913505f agent: fix tegrastats VDD_SYS_GPU parsing
- Parse VDD_SYS_GPU <mW>/<mW> correctly

- Add regression test for GPU@ temp + VDD_SYS_GPU power
2026-01-12 16:12:36 -05:00
Vascolas007
ca8cb78c29 Jetson tegrastats regex pre jetpack5 (#1631)
* feat:Adding regex catching groups for GPU temperature and power in pre jetpack 5
2026-01-12 16:11:22 -05:00
marmar76
8821fb5dd0 fix: some of indonesia translate (#1625)
Co-authored-by: Iskandar, Andreas (contracted) <Andreas.Iskandar@contracted.sampoerna.com>
2026-01-12 15:56:45 -05:00
henrygd
3279a6ca53 agent: add separate glibc build with NVML support (#1618)
purego requires dynamic linking, so split the agent builds:
- Default: static binary without NVML (works on musl/alpine)
- Glibc: dynamic binary with NVML support via purego

Changes:
- Add glibc build tag to conditionally include NVML code
- Add beszel-agent-linux-amd64-glibc build/archive in goreleaser
- Update ghupdate to use glibc binary on glibc systems
- Switch nvidia dockerfile to golang:bookworm with -tags glibc
2026-01-12 15:38:13 -05:00
henrygd
6a1a98d73f update build constraints to exclude nvml collector on arm64 (#1618) 2026-01-11 20:27:34 -05:00
18 changed files with 221 additions and 104 deletions

View File

@@ -76,6 +76,18 @@ builds:
- goos: windows
goarch: riscv64
- id: beszel-agent-linux-amd64-glibc
binary: beszel-agent
main: internal/cmd/agent/agent.go
env:
- CGO_ENABLED=0
flags:
- -tags=glibc
goos:
- linux
goarch:
- amd64
archives:
- id: beszel-agent
formats: [tar.gz]
@@ -89,6 +101,15 @@ archives:
- goos: windows
formats: [zip]
- id: beszel-agent-linux-amd64-glibc
formats: [tar.gz]
ids:
- beszel-agent-linux-amd64-glibc
name_template: >-
{{ .Binary }}_
{{- .Os }}_
{{- .Arch }}_glibc
- id: beszel
formats: [tar.gz]
ids:

View File

@@ -5,6 +5,7 @@ import (
"bytes"
"encoding/json"
"fmt"
"log/slog"
"maps"
"os/exec"
"regexp"
@@ -14,8 +15,6 @@ import (
"time"
"github.com/henrygd/beszel/internal/entities/system"
"log/slog"
)
const (
@@ -137,10 +136,10 @@ func (gm *GPUManager) getJetsonParser() func(output []byte) bool {
// use closure to avoid recompiling the regex
ramPattern := regexp.MustCompile(`RAM (\d+)/(\d+)MB`)
gr3dPattern := regexp.MustCompile(`GR3D_FREQ (\d+)%`)
tempPattern := regexp.MustCompile(`tj@(\d+\.?\d*)C`)
tempPattern := regexp.MustCompile(`(?:tj|GPU)@(\d+\.?\d*)C`)
// Orin Nano / NX do not have GPU specific power monitor
// TODO: Maybe use VDD_IN for Nano / NX and add a total system power chart
powerPattern := regexp.MustCompile(`(GPU_SOC|CPU_GPU_CV) (\d+)mW`)
powerPattern := regexp.MustCompile(`(GPU_SOC|CPU_GPU_CV)\s+(\d+)mW|VDD_SYS_GPU\s+(\d+)/\d+`)
// jetson devices have only one gpu so we'll just initialize here
gpuData := &system.GPUData{Name: "GPU"}
@@ -169,7 +168,13 @@ func (gm *GPUManager) getJetsonParser() func(output []byte) bool {
// Parse power usage
powerMatches := powerPattern.FindSubmatch(output)
if powerMatches != nil {
power, _ := strconv.ParseFloat(string(powerMatches[2]), 64)
// powerMatches[2] is the "(GPU_SOC|CPU_GPU_CV) <N>mW" capture
// powerMatches[3] is the "VDD_SYS_GPU <N>/<N>" capture
powerStr := string(powerMatches[2])
if powerStr == "" {
powerStr = string(powerMatches[3])
}
power, _ := strconv.ParseFloat(powerStr, 64)
gpuData.Power += power / milliwattsInAWatt
}
gpuData.Count++
@@ -232,10 +237,11 @@ func (gm *GPUManager) parseAmdData(output []byte) bool {
totalMemory, _ := strconv.ParseFloat(v.MemoryTotal, 64)
usage, _ := strconv.ParseFloat(v.Usage, 64)
if _, ok := gm.GpuDataMap[v.ID]; !ok {
gm.GpuDataMap[v.ID] = &system.GPUData{Name: v.Name}
id := v.ID
if _, ok := gm.GpuDataMap[id]; !ok {
gm.GpuDataMap[id] = &system.GPUData{Name: v.Name}
}
gpu := gm.GpuDataMap[v.ID]
gpu := gm.GpuDataMap[id]
gpu.Temperature, _ = strconv.ParseFloat(v.Temperature, 64)
gpu.MemoryUsed = bytesToMegabytes(memoryUsage)
gpu.MemoryTotal = bytesToMegabytes(totalMemory)

View File

@@ -27,10 +27,11 @@ func (gm *GPUManager) updateIntelFromStats(sample *intelGpuStats) bool {
defer gm.Unlock()
// only one gpu for now - cmd doesn't provide all by default
gpuData, ok := gm.GpuDataMap["0"]
id := "i0" // prefix with i to avoid conflicts with nvidia card ids
gpuData, ok := gm.GpuDataMap[id]
if !ok {
gpuData = &system.GPUData{Name: "GPU", Engines: make(map[string]float64)}
gm.GpuDataMap["0"] = gpuData
gm.GpuDataMap[id] = gpuData
}
gpuData.Power += sample.PowerGPU

View File

@@ -1,4 +1,4 @@
//go:build (linux || windows) && (amd64 || arm64)
//go:build amd64 && (windows || (linux && glibc))
package agent

View File

@@ -1,4 +1,4 @@
//go:build linux && (amd64 || arm64)
//go:build glibc && linux && amd64
package agent

View File

@@ -1,4 +1,4 @@
//go:build (!linux && !windows) || (!amd64 && !arm64)
//go:build (!linux && !windows) || !amd64 || (linux && !glibc)
package agent

View File

@@ -1,4 +1,4 @@
//go:build windows && (amd64 || arm64)
//go:build windows && amd64
package agent

View File

@@ -307,6 +307,19 @@ func TestParseJetsonData(t *testing.T) {
Count: 1,
},
},
{
name: "orin-style output with GPU@ temp and VDD_SYS_GPU power",
input: "RAM 3276/7859MB (lfb 5x4MB) SWAP 1626/12122MB (cached 181MB) CPU [44%@1421,49%@2031,67%@2034,17%@1420,25%@1419,8%@1420] EMC_FREQ 1%@1866 GR3D_FREQ 0%@114 APE 150 MTS fg 1% bg 1% PLL@42.5C MCPU@42.5C PMIC@50C Tboard@38C GPU@39.5C BCPU@42.5C thermal@41.3C Tdiode@39.25C VDD_SYS_GPU 182/182 VDD_SYS_SOC 730/730 VDD_4V0_WIFI 0/0 VDD_IN 5297/5297 VDD_SYS_CPU 1917/1917 VDD_SYS_DDR 1241/1241",
wantMetrics: &system.GPUData{
Name: "GPU",
MemoryUsed: 3276.0,
MemoryTotal: 7859.0,
Usage: 0.0,
Power: 0.182, // 182mW -> 0.182W
Temperature: 39.5,
Count: 1,
},
},
}
for _, tt := range tests {
@@ -1372,7 +1385,7 @@ func TestIntelUpdateFromStats(t *testing.T) {
ok := gm.updateIntelFromStats(&sample1)
assert.True(t, ok)
gpu := gm.GpuDataMap["0"]
gpu := gm.GpuDataMap["i0"]
require.NotNil(t, gpu)
assert.Equal(t, "GPU", gpu.Name)
assert.EqualValues(t, 10.5, gpu.Power)
@@ -1394,7 +1407,7 @@ func TestIntelUpdateFromStats(t *testing.T) {
ok = gm.updateIntelFromStats(&sample2)
assert.True(t, ok)
gpu = gm.GpuDataMap["0"]
gpu = gm.GpuDataMap["i0"]
require.NotNil(t, gpu)
assert.EqualValues(t, 10.5, gpu.Power)
assert.EqualValues(t, 30.0, gpu.Engines["Render/3D"]) // 20 + 10
@@ -1433,7 +1446,7 @@ echo "298 295 278 51 2.20 3.12 1675 942 5.75 1 2 9.50
t.Fatalf("collectIntelStats error: %v", err)
}
gpu := gm.GpuDataMap["0"]
gpu := gm.GpuDataMap["i0"]
require.NotNil(t, gpu)
// Power should be sum of samples 2-4 (first is skipped): 2.0 + 1.8 + 2.2 = 6.0
assert.EqualValues(t, 6.0, gpu.Power)

View File

@@ -19,11 +19,11 @@ func TestSystemdManagerGetServiceStats(t *testing.T) {
assert.NoError(t, err)
// Test with refresh = true
result := manager.getServiceStats(true)
result := manager.getServiceStats("any-service", true)
assert.Nil(t, result)
// Test with refresh = false
result = manager.getServiceStats(false)
result = manager.getServiceStats("any-service", false)
assert.Nil(t, result)
}

View File

@@ -6,7 +6,7 @@ import "github.com/blang/semver"
const (
// Version is the current version of the application.
Version = "0.18.1"
Version = "0.18.2"
// AppName is the name of the application.
AppName = "beszel"
)

View File

@@ -1,4 +1,4 @@
FROM --platform=$BUILDPLATFORM golang:alpine AS builder
FROM --platform=$BUILDPLATFORM golang:bookworm AS builder
WORKDIR /app
@@ -10,7 +10,7 @@ COPY . ./
# Build
ARG TARGETOS TARGETARCH
RUN CGO_ENABLED=0 GOGC=75 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -ldflags "-w -s" -o /agent ./internal/cmd/agent
RUN CGO_ENABLED=0 GOGC=75 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -tags glibc -ldflags "-w -s" -o /agent ./internal/cmd/agent
# --------------------------
# Smartmontools builder stage

View File

@@ -11,6 +11,7 @@ import (
"log/slog"
"net/http"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
@@ -345,5 +346,32 @@ func archiveSuffix(binaryName, goos, goarch string) string {
if goos == "windows" {
return fmt.Sprintf("%s_%s_%s.zip", binaryName, goos, goarch)
}
// Use glibc build for agent on glibc systems (includes NVML support via purego)
if binaryName == "beszel-agent" && goos == "linux" && goarch == "amd64" && isGlibc() {
return fmt.Sprintf("%s_%s_%s_glibc.tar.gz", binaryName, goos, goarch)
}
return fmt.Sprintf("%s_%s_%s.tar.gz", binaryName, goos, goarch)
}
func isGlibc() bool {
for _, path := range []string{
"/lib64/ld-linux-x86-64.so.2", // common on many distros
"/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2", // Debian/Ubuntu
"/lib/ld-linux-x86-64.so.2", // alternate
} {
if _, err := os.Stat(path); err == nil {
return true
}
}
// Fallback to ldd output when present (musl ldd reports musl, glibc reports GNU libc/glibc).
if lddPath, err := exec.LookPath("ldd"); err == nil {
out, err := exec.Command(lddPath, "--version").CombinedOutput()
if err == nil {
s := strings.ToLower(string(out))
if strings.Contains(s, "gnu libc") || strings.Contains(s, "glibc") {
return true
}
}
}
return false
}

View File

@@ -1,12 +1,12 @@
{
"name": "beszel",
"version": "0.18.1",
"version": "0.18.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "beszel",
"version": "0.18.1",
"version": "0.18.2",
"dependencies": {
"@henrygd/queue": "^1.0.7",
"@henrygd/semaphore": "^0.0.2",

View File

@@ -1,7 +1,7 @@
{
"name": "beszel",
"private": true,
"version": "0.18.1",
"version": "0.18.2",
"type": "module",
"scripts": {
"dev": "vite --host",

View File

@@ -407,23 +407,20 @@ export default memo(function SystemDetail({ id }: { id: string }) {
let hasGpuPowerData = false
if (lastGpus) {
// check if there are any GPUs with engines
for (const id in lastGpus) {
hasGpuData = true
if (lastGpus[id].e !== undefined) {
hasGpuEnginesData = true
break
}
}
// check if there are any GPUs with power data
for (let i = 0; i < systemStats.length && !hasGpuPowerData; i++) {
// check if there are any GPUs at all
hasGpuData = Object.keys(lastGpus).length > 0
// check if there are any GPUs with engines or power data
for (let i = 0; i < systemStats.length && (!hasGpuEnginesData || !hasGpuPowerData); i++) {
const gpus = systemStats[i].stats?.g
if (!gpus) continue
for (const id in gpus) {
if (gpus[id].p !== undefined || gpus[id].pp !== undefined) {
hasGpuPowerData = true
break
if (!hasGpuEnginesData && gpus[id].e !== undefined) {
hasGpuEnginesData = true
}
if (!hasGpuPowerData && (gpus[id].p !== undefined || gpus[id].pp !== undefined)) {
hasGpuPowerData = true
}
if (hasGpuEnginesData && hasGpuPowerData) break
}
}
}
@@ -891,16 +888,30 @@ export default memo(function SystemDetail({ id }: { id: string }) {
})
function GpuEnginesChart({ chartData }: { chartData: ChartData }) {
const dataPoints: DataPoint[] = []
const engines = Object.keys(chartData.systemStats?.at(-1)?.stats.g?.[0]?.e ?? {}).sort()
for (const engine of engines) {
dataPoints.push({
label: engine,
dataKey: ({ stats }: SystemStatsRecord) => stats?.g?.[0]?.e?.[engine] ?? 0,
color: `hsl(${140 + (((engines.indexOf(engine) * 360) / engines.length) % 360)}, 65%, 52%)`,
opacity: 0.35,
})
const { gpuId, engines } = useMemo(() => {
for (let i = chartData.systemStats.length - 1; i >= 0; i--) {
const gpus = chartData.systemStats[i].stats?.g
if (!gpus) continue
for (const id in gpus) {
if (gpus[id].e) {
return { gpuId: id, engines: Object.keys(gpus[id].e).sort() }
}
}
}
return { gpuId: null, engines: [] }
}, [chartData.systemStats])
if (!gpuId) {
return null
}
const dataPoints: DataPoint[] = engines.map((engine, i) => ({
label: engine,
dataKey: ({ stats }: SystemStatsRecord) => stats?.g?.[gpuId]?.e?.[engine] ?? 0,
color: `hsl(${140 + (((i * 360) / engines.length) % 360)}, 65%, 52%)`,
opacity: 0.35,
}))
return (
<LineChartDefault
legend={true}

View File

@@ -22,7 +22,7 @@ msgstr ""
#. placeholder {1}: table.getFilteredRowModel().rows.length
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "{0} of {1} row(s) selected."
msgstr "{0} dari {1} baris dipilih."
msgstr "{0} dari {1} baris terpilih."
#: src/components/routes/system/info-bar.tsx
msgid "{cores, plural, one {# core} other {# cores}}"
@@ -125,11 +125,11 @@ msgstr "Tambah URL"
#: src/components/routes/settings/general.tsx
msgid "Adjust display options for charts."
msgstr "Sesuaikan pengaturan tampilan untuk untuk grafik."
msgstr "Sesuaikan tampilan grafik."
#: src/components/routes/settings/general.tsx
msgid "Adjust the width of the main layout"
msgstr "Sesuaikan lebar layout utama"
msgstr "Sesuaikan lebar layar utama"
#: src/components/command-palette.tsx
#: src/components/command-palette.tsx
@@ -180,7 +180,7 @@ msgstr "Apakah anda yakin?"
#: src/components/copy-to-clipboard.tsx
msgid "Automatic copy requires a secure context."
msgstr "Menyalin otomatis memerlukan konteks yang aman."
msgstr "Copy memerlukan https."
#: src/components/routes/system.tsx
msgid "Average"
@@ -215,7 +215,7 @@ msgstr "Rata-rata utilisasi {0}"
#: src/components/routes/system.tsx
msgid "Average utilization of GPU engines"
msgstr "Rata-rata utilisasi mesin GPU"
msgstr "Rata-rata utilisasi GPU"
#: src/components/command-palette.tsx
#: src/components/navbar.tsx
@@ -225,12 +225,12 @@ msgstr "Cadangan"
#: src/components/routes/system.tsx
#: src/lib/alerts.ts
msgid "Bandwidth"
msgstr "Pita lebar"
msgstr "Bandwith"
#. Battery label in systems table header
#: src/components/systems-table/systems-table-columns.tsx
msgid "Bat"
msgstr "Bat"
msgstr "Baterai"
#: src/components/routes/system.tsx
#: src/lib/alerts.ts
@@ -258,7 +258,7 @@ msgstr "Di bawah {0}{1} dalam {2, plural, one {# menit} other {# menit}} terakhi
#: src/components/login/auth-form.tsx
msgid "Beszel supports OpenID Connect and many OAuth2 authentication providers."
msgstr "Beszel mendukung OpenID Connecnt dan banyak penyedia autentikasi OAuth2."
msgstr "Beszel mendukung OpenID Connect dan OAuth2 dari berbagai penyedia layanan."
#: src/components/routes/settings/notifications.tsx
msgid "Beszel uses <0>Shoutrrr</0> to integrate with popular notification services."
@@ -330,7 +330,7 @@ msgstr "Ubah pengaturan umum aplikasi."
#: src/components/routes/system.tsx
msgid "Charge"
msgstr "Isi"
msgstr "Isi baterai"
#. Context: Battery state
#: src/lib/i18n.ts
@@ -339,19 +339,19 @@ msgstr "Sedang mengisi"
#: src/components/routes/settings/general.tsx
msgid "Chart options"
msgstr "Pengaturan grafik"
msgstr "Pilihan grafik"
#: src/components/login/forgot-pass-form.tsx
msgid "Check {email} for a reset link."
msgstr "Periksa {email} untuk tautan atur ulang."
msgstr "Periksa {email} untuk tautan atur ulang password."
#: src/components/routes/settings/layout.tsx
msgid "Check logs for more details."
msgstr "Periksa catatan untuk lebih detail."
msgstr "Periksa riwayat untuk lebih detail."
#: src/components/routes/settings/notifications.tsx
msgid "Check your notification service"
msgstr "Periksa penyedia jasa notifikasi anda"
msgstr "Periksa jasa penyedia notifikasi anda"
#: src/components/containers-table/containers-table.tsx
#: src/components/routes/system/smart-table.tsx
@@ -500,11 +500,11 @@ msgstr "Kritis (%)"
#: src/components/routes/system/network-sheet.tsx
msgid "Cumulative Download"
msgstr "Download Kumulatif"
msgstr "Akumulasi Download"
#: src/components/routes/system/network-sheet.tsx
msgid "Cumulative Upload"
msgstr "Upload Kumulatif"
msgstr "Akumulasi Upload"
#. Context: Battery state
#: src/components/routes/system.tsx
@@ -523,7 +523,7 @@ msgstr "Harian"
#: src/components/routes/settings/general.tsx
msgid "Default time period"
msgstr "Periode waktu default"
msgstr "Standar waktu"
#: src/components/routes/settings/alerts-history-data-table.tsx
#: src/components/routes/settings/quiet-hours.tsx
@@ -534,7 +534,7 @@ msgstr "Hapus"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Delete fingerprint"
msgstr "Hapus sidik jari"
msgstr "Hapus fingerprint"
#: src/components/systemd-table/systemd-table.tsx
msgid "Description"
@@ -551,7 +551,7 @@ msgstr "Perangkat"
#. Context: Battery state
#: src/lib/i18n.ts
msgid "Discharging"
msgstr "Sedang mengosongkan"
msgstr "Sedang tidak di charge"
#: src/components/systems-table/systems-table-columns.tsx
msgid "Disk"
@@ -615,12 +615,12 @@ msgstr "Durasi"
#: src/components/routes/settings/quiet-hours.tsx
#: src/components/systems-table/systems-table-columns.tsx
msgid "Edit"
msgstr "Edit"
msgstr "Ubah"
#: src/components/add-system.tsx
#: src/components/routes/settings/quiet-hours.tsx
msgid "Edit {foo}"
msgstr "Edit {foo}"
msgstr "Ubah {foo}"
#: src/components/login/auth-form.tsx
#: src/components/login/forgot-pass-form.tsx
@@ -652,7 +652,7 @@ msgstr "Masukkan alamat email..."
#: src/components/login/otp-forms.tsx
msgid "Enter your one-time password."
msgstr "Masukkan kata sandi satu kali anda."
msgstr "Masukkan otp anda."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Ephemeral"
@@ -694,15 +694,15 @@ msgstr "Kedaluwarsa setelah satu jam atau saat restart hub."
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Export"
msgstr "Ekspor"
msgstr "Export"
#: src/components/routes/settings/config-yaml.tsx
msgid "Export configuration"
msgstr "Ekspor konfigurasi"
msgstr "Export konfigurasi"
#: src/components/routes/settings/config-yaml.tsx
msgid "Export your current systems configuration."
msgstr "Ekspor konfigurasi sistem anda saat ini."
msgstr "Export konfigurasi sistem anda saat ini."
#: src/components/routes/settings/general.tsx
msgid "Fahrenheit (°F)"
@@ -728,7 +728,7 @@ msgstr "Gagal menyimpan pengaturan"
#: src/components/routes/settings/notifications.tsx
msgid "Failed to send test notification"
msgstr "Gagal mengirim notifikasi tes"
msgstr "Gagal mengirim tes notifikasi"
#: src/components/alerts/alerts-sheet.tsx
msgid "Failed to update alert"
@@ -750,7 +750,7 @@ msgstr "Filter..."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Fingerprint"
msgstr "Sidik jari"
msgstr "Fingerprint"
#: src/components/routes/system/smart-table.tsx
msgid "Firmware"
@@ -787,7 +787,7 @@ msgstr "Global"
#: src/components/routes/system.tsx
msgid "GPU Engines"
msgstr "Mesin GPU"
msgstr "GPU"
#: src/components/routes/system.tsx
msgid "GPU Power Draw"
@@ -799,7 +799,7 @@ msgstr "Penggunaan GPU"
#: src/components/systems-table/systems-table.tsx
msgid "Grid"
msgstr "Grid"
msgstr "Kartu"
#: src/components/containers-table/containers-table-columns.tsx
msgid "Health"
@@ -843,11 +843,11 @@ msgstr "Bahasa"
#: src/components/systems-table/systems-table.tsx
msgid "Layout"
msgstr "Layout"
msgstr "Tampilan"
#: src/components/routes/settings/general.tsx
msgid "Layout width"
msgstr "Lebar layout"
msgstr "Lebar tampilan"
#: src/components/systemd-table/systemd-table.tsx
msgid "Lifecycle"
@@ -877,11 +877,11 @@ msgstr "Rata-rata Beban 5m"
#. Short label for load average
#: src/components/systems-table/systems-table-columns.tsx
msgid "Load Avg"
msgstr "Rata Beban"
msgstr "Rata-rata Beban"
#: src/components/systemd-table/systemd-table.tsx
msgid "Load state"
msgstr "Status beban"
msgstr "Beban saat ini"
#: src/components/systemd-table/systemd-table.tsx
msgid "Loading..."
@@ -889,7 +889,7 @@ msgstr "Memuat..."
#: src/components/navbar.tsx
msgid "Log Out"
msgstr "Keluar"
msgstr "Log Out"
#: src/components/login/login.tsx
msgid "Login"
@@ -969,7 +969,7 @@ msgstr "Nama"
#: src/components/containers-table/containers-table-columns.tsx
#: src/components/systems-table/systems-table-columns.tsx
msgid "Net"
msgstr "Net"
msgstr "Jaringan"
#: src/components/routes/system.tsx
msgid "Network traffic of docker containers"
@@ -1014,7 +1014,7 @@ msgstr "Tidak ada atribut S.M.A.R.T. yang tersedia untuk perangkat ini."
#: src/components/systems-table/systems-table.tsx
#: src/components/systems-table/systems-table.tsx
msgid "No systems found."
msgstr "Tidak ada sistem ditemukan."
msgstr "Sistem tidak ditemukan."
#: src/components/command-palette.tsx
#: src/components/routes/settings/layout.tsx
@@ -1033,11 +1033,11 @@ msgstr "Pada setiap restart, sistem dalam database akan diperbarui untuk mencoco
#: src/components/routes/settings/quiet-hours.tsx
#: src/components/routes/settings/quiet-hours.tsx
msgid "One-time"
msgstr "Sekali"
msgstr "Sekali pakai"
#: src/components/login/auth-form.tsx
msgid "One-time password"
msgstr "Kata sandi sekali pakai"
msgstr "Kata sandi sekali pakai (OTP)"
#: src/components/routes/settings/quiet-hours.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
@@ -1123,7 +1123,7 @@ msgstr "Permanen"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Persistence"
msgstr "Ketekunan"
msgstr "Tetap berlaku"
#: src/components/routes/settings/notifications.tsx
msgid "Please <0>configure an SMTP server</0> to ensure alerts are delivered."
@@ -1174,7 +1174,7 @@ msgstr "Utilisasi tepat pada waktu yang direkam"
#: src/components/routes/settings/general.tsx
msgid "Preferred Language"
msgstr "Bahasa Pilihan"
msgstr "Pilihan Bahasa"
#: src/components/systemd-table/systemd-table.tsx
msgid "Process started"
@@ -1203,7 +1203,7 @@ msgstr "Diterima"
#: src/components/containers-table/containers-table.tsx
#: src/components/routes/system/smart-table.tsx
msgid "Refresh"
msgstr "Refresh"
msgstr "Muat ulang"
#: src/components/systemd-table/systemd-table.tsx
msgid "Relationships"
@@ -1250,7 +1250,7 @@ msgstr "Root"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Rotate token"
msgstr "Putar token"
msgstr "Ganti ulang token"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "Rows per page"
@@ -1291,7 +1291,7 @@ msgstr "Jadwal"
#: src/components/routes/settings/quiet-hours.tsx
msgid "Schedule quiet hours where notifications will not be sent, such as during maintenance periods."
msgstr "Jadwalkan jam tenang dimana notifikasi tidak akan dikirim, seperti selama periode pemeliharaan."
msgstr "Jadwalkan jam tenang dimana notifikasi tidak akan dikirim, seperti saat periode pemeliharaan."
#: src/components/routes/settings/quiet-hours.tsx
msgid "Schedule quiet hours where notifications will not be sent."
@@ -1430,7 +1430,7 @@ msgstr "Tugas"
#: src/components/routes/system/smart-table.tsx
#: src/components/systems-table/systems-table-columns.tsx
msgid "Temp"
msgstr "Temp"
msgstr "Temperatur"
#: src/components/routes/system.tsx
#: src/lib/alerts.ts
@@ -1459,7 +1459,7 @@ msgstr "Kemudian masuk ke backend dan reset kata sandi akun pengguna anda di tab
#: src/components/systems-table/systems-table-columns.tsx
msgid "This action cannot be undone. This will permanently delete all current records for {name} from the database."
msgstr ""
msgstr "Aksi ini tidak dapat di kembalikan. ini akan menghapus permanen semua record {name} dari database"
#: src/components/routes/settings/alerts-history-data-table.tsx
msgid "This will permanently delete all selected records from the database."
@@ -1484,11 +1484,11 @@ msgstr "Ke email"
#: src/components/routes/system/info-bar.tsx
#: src/components/routes/system/info-bar.tsx
msgid "Toggle grid"
msgstr "Toggle grid"
msgstr "Ganti tampilan"
#: src/components/mode-toggle.tsx
msgid "Toggle theme"
msgstr "Toggle tema"
msgstr "Ganti tema"
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
@@ -1499,15 +1499,15 @@ msgstr "Token"
#: src/components/routes/settings/layout.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens & Fingerprints"
msgstr "Token & Sidik Jari"
msgstr "Token & Fingerprint"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens allow agents to connect and register. Fingerprints are stable identifiers unique to each system, set on first connection."
msgstr "Token memungkinkan agen untuk terhubung dan mendaftar. Sidik jari adalah pengidentifikasi stabil unik untuk setiap sistem, ditetapkan pada koneksi pertama."
msgstr "Token memungkinkan agen untuk terhubung dan mendaftar. Fingerprint adalah sistem indentifikasi yang stabil dan unik untuk setiap sistem, diatur pada koneksi pertama."
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "Tokens and fingerprints are used to authenticate WebSocket connections to the hub."
msgstr "Token dan sidik jari digunakan untuk mengautentikasi koneksi WebSocket ke hub."
msgstr "Token dan Fingerprint digunakan untuk mengautentikasi koneksi WebSocket ke hub."
#: src/components/ui/chart.tsx
#: src/components/ui/chart.tsx
@@ -1553,11 +1553,11 @@ msgstr "Dipicu ketika sensor apa pun melebihi ambang batas"
#: src/lib/alerts.ts
msgid "Triggers when battery charge drops below a threshold"
msgstr "Dipicu ketika muatan baterai turun di bawah ambang batas"
msgstr "Dipicu ketika baterai turun di bawah ambang batas"
#: src/lib/alerts.ts
msgid "Triggers when combined up/down exceeds a threshold"
msgstr "Dipicu ketika kombinasi up/down melebihi ambang batas"
msgstr "Dipicu ketika up atau down melebihi ambang batas"
#: src/lib/alerts.ts
msgid "Triggers when CPU usage exceeds a threshold"
@@ -1592,7 +1592,7 @@ msgstr "File unit"
#. Temperature / network units
#: src/components/routes/settings/general.tsx
msgid "Unit preferences"
msgstr "Preferensi unit"
msgstr "Pengaturan satuan"
#: src/components/command-palette.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx
@@ -1613,11 +1613,11 @@ msgstr "Tidak terbatas"
#: src/components/routes/system/info-bar.tsx
#: src/components/systems-table/systems-table-columns.tsx
msgid "Up"
msgstr "Up"
msgstr "Nyala"
#: src/components/systems-table/systems-table.tsx
msgid "Up ({upSystemsLength})"
msgstr "Up ({upSystemsLength})"
msgstr "Nyala selama ({upSystemsLength})"
#: src/components/routes/settings/quiet-hours.tsx
msgid "Update"
@@ -1682,7 +1682,7 @@ msgstr "Lihat 200 peringatan terbaru anda."
#: src/components/systems-table/systems-table.tsx
msgid "Visible Fields"
msgstr "Field yang Terlihat"
msgstr "Metrik yang Terlihat"
#: src/components/routes/system.tsx
msgid "Waiting for enough records to display"
@@ -1706,11 +1706,11 @@ msgstr "Ambang peringatan"
#: src/components/routes/settings/notifications.tsx
msgid "Webhook / Push notifications"
msgstr "Notifikasi Webhook / Push"
msgstr "Webhook / Push notifikasi"
#: src/components/routes/settings/tokens-fingerprints.tsx
msgid "When enabled, this token allows agents to self-register without prior system creation."
msgstr "Ketika diaktifkan, token ini memungkinkan agen untuk mendaftar sendiri tanpa pembuatan sistem sebelumnya."
msgstr "Ketika diaktifkan, token ini memungkinkan agen untuk mendaftar sendiri tanpa pembuatan sistem."
#: src/components/add-system.tsx
#: src/components/routes/settings/tokens-fingerprints.tsx

View File

@@ -1,3 +1,19 @@
## 0.18.2
- Add separate dynamically linked glibc build for Linux. (#1618)
- Fix GPU ID collision between Intel and NVIDIA collectors. (#1522)
- Only hide GPU engine graph if entire usage is 0%. (#1624)
- Add Jetson tegrastats regex support for pre-Jetpack 5 versions. (#1631)
- Improve Indonesian translations. (#1625)
## 0.18.1
- Fix bug in 0.18.0 where all containers were cleared from the "All Containers" page when any system returned no containers.
## 0.18.0
- Add experimental NVML GPU collector. (#1522, #1587)

View File

@@ -12,6 +12,24 @@ is_freebsd() {
[ "$(uname -s)" = "FreeBSD" ]
}
is_glibc() {
# Prefer glibc-enabled agent (NVML via purego) on linux/amd64 glibc systems.
# Check common dynamic loader paths first (fast + reliable).
for p in \
/lib64/ld-linux-x86-64.so.2 \
/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 \
/lib/ld-linux-x86-64.so.2; do
[ -e "$p" ] && return 0
done
# Fallback to ldd output if available.
if command -v ldd >/dev/null 2>&1; then
ldd --version 2>&1 | grep -qiE 'gnu libc|glibc' && return 0
fi
return 1
}
# If SELinux is enabled, set the context of the binary
set_selinux_context() {
@@ -598,6 +616,9 @@ echo "Downloading and installing the agent..."
OS=$(uname -s | sed -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/')
ARCH=$(detect_architecture)
FILE_NAME="beszel-agent_${OS}_${ARCH}.tar.gz"
if [ "$OS" = "linux" ] && [ "$ARCH" = "amd64" ] && is_glibc; then
FILE_NAME="beszel-agent_${OS}_${ARCH}_glibc.tar.gz"
fi
# Determine version to install
if [ "$VERSION" = "latest" ]; then