mirror of
https://github.com/itdoginfo/podkop.git
synced 2025-12-07 20:16:53 +03:00
feat: add podkop log watcher with alerts
This commit is contained in:
5
fe-app-podkop/src/luci.d.ts
vendored
5
fe-app-podkop/src/luci.d.ts
vendored
@@ -39,6 +39,11 @@ declare global {
|
|||||||
const ui = {
|
const ui = {
|
||||||
showModal: (_title: stirng, _content: HtmlElement) => undefined,
|
showModal: (_title: stirng, _content: HtmlElement) => undefined,
|
||||||
hideModal: () => undefined,
|
hideModal: () => undefined,
|
||||||
|
addNotification: (
|
||||||
|
_title: string,
|
||||||
|
_children: HtmlElement | HtmlElement[],
|
||||||
|
_className?: string,
|
||||||
|
) => undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import { TabServiceInstance } from './tab.service';
|
import { TabServiceInstance } from './tab.service';
|
||||||
import { store } from './store.service';
|
import { store } from './store.service';
|
||||||
import { logger } from './logger.service';
|
import { logger } from './logger.service';
|
||||||
|
import { PodkopLogWatcher } from './podkopLogWatcher.service';
|
||||||
|
import { PodkopShellMethods } from '../methods';
|
||||||
|
|
||||||
export function coreService() {
|
export function coreService() {
|
||||||
TabServiceInstance.onChange((activeId, tabs) => {
|
TabServiceInstance.onChange((activeId, tabs) => {
|
||||||
@@ -12,4 +14,28 @@ export function coreService() {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const watcher = PodkopLogWatcher.getInstance();
|
||||||
|
|
||||||
|
watcher.init(
|
||||||
|
async () => {
|
||||||
|
const logs = await PodkopShellMethods.checkLogs();
|
||||||
|
|
||||||
|
if (logs.success) {
|
||||||
|
return logs.data as string;
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
},
|
||||||
|
{
|
||||||
|
intervalMs: 3000,
|
||||||
|
onNewLog: (line) => {
|
||||||
|
if (line.includes('[critical]')) {
|
||||||
|
ui.addNotification('Podkop Critical', E('div', {}, line), 'error');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
watcher.start();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
import { logger } from './logger.service';
|
||||||
|
|
||||||
|
export type LogFetcher = () => Promise<string> | string;
|
||||||
|
|
||||||
|
export interface PodkopLogWatcherOptions {
|
||||||
|
intervalMs?: number;
|
||||||
|
onNewLog?: (line: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PodkopLogWatcher {
|
||||||
|
private static instance: PodkopLogWatcher;
|
||||||
|
private fetcher?: LogFetcher;
|
||||||
|
private onNewLog?: (line: string) => void;
|
||||||
|
private intervalMs = 5000;
|
||||||
|
private lastLines = new Set<string>();
|
||||||
|
private timer?: ReturnType<typeof setInterval>;
|
||||||
|
private running = false;
|
||||||
|
|
||||||
|
private constructor() {}
|
||||||
|
|
||||||
|
static getInstance(): PodkopLogWatcher {
|
||||||
|
if (!PodkopLogWatcher.instance) {
|
||||||
|
PodkopLogWatcher.instance = new PodkopLogWatcher();
|
||||||
|
}
|
||||||
|
return PodkopLogWatcher.instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
init(fetcher: LogFetcher, options?: PodkopLogWatcherOptions): void {
|
||||||
|
this.fetcher = fetcher;
|
||||||
|
this.onNewLog = options?.onNewLog;
|
||||||
|
this.intervalMs = options?.intervalMs ?? 5000;
|
||||||
|
}
|
||||||
|
|
||||||
|
async checkOnce(): Promise<void> {
|
||||||
|
if (!this.fetcher) {
|
||||||
|
logger.warn('[PodkopLogWatcher]', 'fetcher not found');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const raw = await this.fetcher();
|
||||||
|
const lines = raw.split('\n').filter(Boolean);
|
||||||
|
|
||||||
|
for (const line of lines) {
|
||||||
|
if (!this.lastLines.has(line)) {
|
||||||
|
this.lastLines.add(line);
|
||||||
|
|
||||||
|
if (this.onNewLog) {
|
||||||
|
this.onNewLog(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.lastLines.size > 500) {
|
||||||
|
const arr = Array.from(this.lastLines);
|
||||||
|
this.lastLines = new Set(arr.slice(-500));
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
logger.error('[PodkopLogWatcher]', 'failed to read logs:', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
start(): void {
|
||||||
|
if (this.running) return;
|
||||||
|
if (!this.fetcher) {
|
||||||
|
logger.warn('[PodkopLogWatcher]', 'Try to start without fetcher.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.running = true;
|
||||||
|
this.timer = setInterval(() => this.checkOnce(), this.intervalMs);
|
||||||
|
logger.info(
|
||||||
|
`[PodkopLogWatcher]', 'Started with interval ${this.intervalMs} ms`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
stop(): void {
|
||||||
|
if (!this.running) return;
|
||||||
|
this.running = false;
|
||||||
|
if (this.timer) clearInterval(this.timer);
|
||||||
|
logger.info('[PodkopLogWatcher]', 'Stopped');
|
||||||
|
}
|
||||||
|
|
||||||
|
reset(): void {
|
||||||
|
this.lastLines.clear();
|
||||||
|
logger.info('[PodkopLogWatcher]', 'logs history was reset');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1234,6 +1234,72 @@ var Logger = class {
|
|||||||
};
|
};
|
||||||
var logger = new Logger();
|
var logger = new Logger();
|
||||||
|
|
||||||
|
// src/podkop/services/podkopLogWatcher.service.ts
|
||||||
|
var PodkopLogWatcher = class _PodkopLogWatcher {
|
||||||
|
constructor() {
|
||||||
|
this.intervalMs = 5e3;
|
||||||
|
this.lastLines = /* @__PURE__ */ new Set();
|
||||||
|
this.running = false;
|
||||||
|
}
|
||||||
|
static getInstance() {
|
||||||
|
if (!_PodkopLogWatcher.instance) {
|
||||||
|
_PodkopLogWatcher.instance = new _PodkopLogWatcher();
|
||||||
|
}
|
||||||
|
return _PodkopLogWatcher.instance;
|
||||||
|
}
|
||||||
|
init(fetcher, options) {
|
||||||
|
this.fetcher = fetcher;
|
||||||
|
this.onNewLog = options?.onNewLog;
|
||||||
|
this.intervalMs = options?.intervalMs ?? 5e3;
|
||||||
|
}
|
||||||
|
async checkOnce() {
|
||||||
|
if (!this.fetcher) {
|
||||||
|
logger.warn("[PodkopLogWatcher]", "fetcher not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const raw = await this.fetcher();
|
||||||
|
const lines = raw.split("\n").filter(Boolean);
|
||||||
|
for (const line of lines) {
|
||||||
|
if (!this.lastLines.has(line)) {
|
||||||
|
this.lastLines.add(line);
|
||||||
|
if (this.onNewLog) {
|
||||||
|
this.onNewLog(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.lastLines.size > 500) {
|
||||||
|
const arr = Array.from(this.lastLines);
|
||||||
|
this.lastLines = new Set(arr.slice(-500));
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
logger.error("[PodkopLogWatcher]", "failed to read logs:", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
start() {
|
||||||
|
if (this.running) return;
|
||||||
|
if (!this.fetcher) {
|
||||||
|
logger.warn("[PodkopLogWatcher]", "Try to start without fetcher.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.running = true;
|
||||||
|
this.timer = setInterval(() => this.checkOnce(), this.intervalMs);
|
||||||
|
logger.info(
|
||||||
|
`[PodkopLogWatcher]', 'Started with interval ${this.intervalMs} ms`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
stop() {
|
||||||
|
if (!this.running) return;
|
||||||
|
this.running = false;
|
||||||
|
if (this.timer) clearInterval(this.timer);
|
||||||
|
logger.info("[PodkopLogWatcher]", "Stopped");
|
||||||
|
}
|
||||||
|
reset() {
|
||||||
|
this.lastLines.clear();
|
||||||
|
logger.info("[PodkopLogWatcher]", "logs history was reset");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// src/podkop/services/core.service.ts
|
// src/podkop/services/core.service.ts
|
||||||
function coreService() {
|
function coreService() {
|
||||||
TabServiceInstance.onChange((activeId, tabs) => {
|
TabServiceInstance.onChange((activeId, tabs) => {
|
||||||
@@ -1245,6 +1311,25 @@ function coreService() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
const watcher = PodkopLogWatcher.getInstance();
|
||||||
|
watcher.init(
|
||||||
|
async () => {
|
||||||
|
const logs = await PodkopShellMethods.checkLogs();
|
||||||
|
if (logs.success) {
|
||||||
|
return logs.data;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
},
|
||||||
|
{
|
||||||
|
intervalMs: 3e3,
|
||||||
|
onNewLog: (line) => {
|
||||||
|
if (line.includes("[critical]")) {
|
||||||
|
ui.addNotification("Podkop Critical", E("div", {}, line), "error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
watcher.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
// src/podkop/services/socket.service.ts
|
// src/podkop/services/socket.service.ts
|
||||||
|
|||||||
Reference in New Issue
Block a user