feat(logs): добавить раздел логов с историей и живым потоком
Docker images / prepare-release (push) Successful in 9s
Docker images / backend-test (push) Successful in 4m35s
Docker images / frontend-image (push) Successful in 3m29s
Docker images / updater-image (push) Successful in 41s
Docker images / netflow-agent-image (push) Successful in 34s
Docker images / backend-image (push) Successful in 1m44s
Docker images / publish-release (push) Successful in 10s
Docker images / notify-webhook (push) Successful in 2s

This commit is contained in:
Denozordec committed 2026-10-16 22:13:48 +07:00
1 parent e461dc21bd
commit 5efd0339fb
37 files changed
+1399 -7

No files matched your search

+1 -1
View File
@@ -232,7 +232,7 @@ export function permissionForPath(pathname: string): string | null {
return "mm:dashboard:read"
}
if (pathname.startsWith("/probes")) return "mm:servers:read"
if (pathname.startsWith("/terminal")) return "mm:servers:read"
if (pathname.startsWith("/terminal") || pathname.startsWith("/logs")) return "mm:servers:read"
if (pathname.startsWith("/servers")) return "mm:servers:read"
if (pathname.startsWith("/filters") || pathname.startsWith("/gre")) {
return "mm:filters:read"
+1
View File
@@ -42,6 +42,7 @@ export const navigationItems: NavigationItem[] = [
{ id: "certificates", title: "Сертификаты", group: "Управление", url: "/certificates", icon: BadgeCheckIcon, keywords: ["ssl","tls","cert","pki","x509"] },
{ id: "backups", title: "Бэкапы", group: "Управление", url: "/backups", icon: HardDriveIcon, keywords: ["backup","резервная копия"] },
// Инструменты
{ id: "logs", title: "Логи", group: "Инструменты", url: "/logs", icon: ActivityIcon, keywords: ["logs", "журнал", "события", "syslog", "ошибки"] },
{ id: "route-optimizer", title: "Оптимизатор маршрутов", group: "Инструменты", url: "/route-optimizer", icon: RouteIcon, keywords: ["routing","wan","failover","переключение"] },
{ id: "ospf", title: "OSPF", group: "Инструменты", url: "/ospf", icon: GitForkIcon, keywords: ["ospf","igp","neighbors","lsa"] },
{ id: "bgp", title: "BGP", group: "Инструменты", url: "/bgp", icon: GitMergeIcon, keywords: ["bgp","ebgp","ibgp","сессии","peers"] },
+10 -1
View File
@@ -114,7 +114,16 @@ export interface GeoipUpdateRunSnapshot {
errors: string[]
}
export interface RouterLogsRunSnapshot {
v: 1
job: "router_logs"
sampledAt: string
skipped?: boolean
errors: string[]
servers: { serverId: number; name: string; added: number; gap: boolean; error?: string }[]
}
export type SchedulerRunSnapshot =
| RouterLogsRunSnapshot
| TrafficRunSnapshot
| ResourcesRunSnapshot
| PingRunSnapshot
@@ -234,7 +243,7 @@ export function parseSchedulerRunSnapshot(raw: unknown): SchedulerRunSnapshot |
if (o.skipped !== undefined && typeof o.skipped !== "boolean") return null
if (o.fatalError !== undefined && typeof o.fatalError !== "string") return null
for (const field of ["errors", "eventErrors"]) if (o[field] !== undefined && (!Array.isArray(o[field]) || !(o[field] as unknown[]).every(error => typeof error === "string"))) return null
const arrays: Record<string, string> = { traffic: "servers", uptime_resources: "servers", servers_rest_ping: "servers", uptime_ping: "probes", uptime_speed: "runs" }
const arrays: Record<string, string> = { router_logs: "servers", traffic: "servers", uptime_resources: "servers", servers_rest_ping: "servers", uptime_ping: "probes", uptime_speed: "runs" }
if (Object.hasOwn(arrays, o.job)) {
if (!Array.isArray(o[arrays[o.job]])) return null
} else {
+3
View File
@@ -2,6 +2,7 @@
/** Последний ключ — движок оповещений (читает БД после коллекторов; см. описание `alert_engine`). */
export const SCHEDULER_JOB_KEYS = [
"router_logs",
"traffic",
"servers_rest_ping",
"uptime_resources",
@@ -17,6 +18,7 @@ export const SCHEDULER_JOB_KEYS = [
export type SchedulerJobKey = (typeof SCHEDULER_JOB_KEYS)[number]
export const SCHEDULER_JOB_LABELS: Record<string, string> = {
router_logs: "Логи MikroTik",
traffic: "Трафик",
servers_rest_ping: "Серверы: REST API",
uptime_resources: "Uptime: ресурсы",
@@ -32,6 +34,7 @@ export const SCHEDULER_JOB_LABELS: Record<string, string> = {
/** Кратко — для раскрытой карточки прогона и подсказок. */
export const SCHEDULER_JOB_DESCRIPTIONS: Record<string, string> = {
router_logs: "REST-сбор буфера memory в PostgreSQL. Параметры — в панели «Логи MikroTik» ниже; live ускоряет опрос выбранного устройства до 2 секунд.",
traffic: "Опрос интерфейсов RouterOS, запись сэмплов трафика в PostgreSQL.",
servers_rest_ping:
"Проверка доступности каталога серверов: GET /system/identity (RouterOS REST), замер задержки без полного опроса.",