mirror of
https://github.com/Dokploy/dokploy.git
synced 2026-06-20 14:45:42 +02:00
The search filter on the Requests tab was incorrectly filtering by RequestPath instead of RequestHost, causing "filter by name" to match URL paths rather than hostnames. Updated the placeholder text to reflect the correct field being searched. Fixes #4249
173 lines
4.0 KiB
TypeScript
173 lines
4.0 KiB
TypeScript
import _ from "lodash";
|
|
import type { LogEntry } from "./types";
|
|
|
|
interface HourlyData {
|
|
hour: string;
|
|
count: number;
|
|
}
|
|
|
|
export function processLogs(
|
|
logString: string,
|
|
dateRange?: { start?: string; end?: string },
|
|
): HourlyData[] {
|
|
if (_.isEmpty(logString)) {
|
|
return [];
|
|
}
|
|
|
|
const hourlyData = _(logString)
|
|
.split("\n")
|
|
.filter((line) => {
|
|
const trimmed = line.trim();
|
|
// Check if the line starts with { and ends with } to ensure it's a potential JSON object
|
|
return trimmed !== "" && trimmed.startsWith("{") && trimmed.endsWith("}");
|
|
})
|
|
.map((entry) => {
|
|
try {
|
|
const log: LogEntry = JSON.parse(entry);
|
|
if (log.ServiceName === "dokploy-service-app@file") {
|
|
return null;
|
|
}
|
|
const date = new Date(log.StartUTC);
|
|
|
|
if (dateRange?.start || dateRange?.end) {
|
|
const logDate = date.getTime();
|
|
const start = dateRange?.start
|
|
? new Date(dateRange.start).getTime()
|
|
: 0;
|
|
const end = dateRange?.end
|
|
? new Date(dateRange.end).getTime()
|
|
: Number.POSITIVE_INFINITY;
|
|
if (logDate < start || logDate > end) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
return `${date.toISOString().slice(0, 13)}:00:00Z`;
|
|
} catch (error) {
|
|
console.error("Error parsing log entry:", error);
|
|
return null;
|
|
}
|
|
})
|
|
.compact()
|
|
.countBy()
|
|
.map((count, hour) => ({ hour, count }))
|
|
.value();
|
|
|
|
return _.sortBy(hourlyData, (entry) => new Date(entry.hour).getTime());
|
|
}
|
|
|
|
interface PageInfo {
|
|
pageIndex: number;
|
|
pageSize: number;
|
|
}
|
|
|
|
interface SortInfo {
|
|
id: string;
|
|
desc: boolean;
|
|
}
|
|
|
|
export function parseRawConfig(
|
|
rawConfig: string,
|
|
page?: PageInfo,
|
|
sort?: SortInfo,
|
|
search?: string,
|
|
status?: string[],
|
|
dateRange?: { start?: string; end?: string },
|
|
): { data: LogEntry[]; totalCount: number } {
|
|
try {
|
|
if (_.isEmpty(rawConfig)) {
|
|
return { data: [], totalCount: 0 };
|
|
}
|
|
|
|
// Split logs into chunks to avoid memory issues
|
|
let parsedLogs = _(rawConfig)
|
|
.split("\n")
|
|
.filter((line) => {
|
|
const trimmed = line.trim();
|
|
return (
|
|
trimmed !== "" && trimmed.startsWith("{") && trimmed.endsWith("}")
|
|
);
|
|
})
|
|
.map((line) => {
|
|
try {
|
|
return JSON.parse(line) as LogEntry;
|
|
} catch (error) {
|
|
console.error("Error parsing log line:", error);
|
|
return null;
|
|
}
|
|
})
|
|
.compact()
|
|
.value();
|
|
|
|
// Filter out Dokploy dashboard requests
|
|
parsedLogs = parsedLogs.filter(
|
|
(log) => log.ServiceName !== "dokploy-service-app@file",
|
|
);
|
|
|
|
// Apply date range filter if provided
|
|
if (dateRange?.start || dateRange?.end) {
|
|
parsedLogs = parsedLogs.filter((log) => {
|
|
const logDate = new Date(log.StartUTC).getTime();
|
|
const start = dateRange?.start
|
|
? new Date(dateRange.start).getTime()
|
|
: 0;
|
|
const end = dateRange?.end
|
|
? new Date(dateRange.end).getTime()
|
|
: Number.POSITIVE_INFINITY;
|
|
return logDate >= start && logDate <= end;
|
|
});
|
|
}
|
|
|
|
if (search) {
|
|
parsedLogs = parsedLogs.filter((log) =>
|
|
log.RequestHost.toLowerCase().includes(search.toLowerCase()),
|
|
);
|
|
}
|
|
|
|
if (status && status.length > 0) {
|
|
parsedLogs = parsedLogs.filter((log) =>
|
|
status.some((range) => isStatusInRange(log.DownstreamStatus, range)),
|
|
);
|
|
}
|
|
|
|
const totalCount = parsedLogs.length;
|
|
|
|
if (sort) {
|
|
parsedLogs = _.orderBy(
|
|
parsedLogs,
|
|
[sort.id],
|
|
[sort.desc ? "desc" : "asc"],
|
|
);
|
|
} else {
|
|
parsedLogs = _.orderBy(parsedLogs, ["time"], ["desc"]);
|
|
}
|
|
|
|
if (page) {
|
|
const startIndex = page.pageIndex * page.pageSize;
|
|
parsedLogs = parsedLogs.slice(startIndex, startIndex + page.pageSize);
|
|
}
|
|
|
|
return { data: parsedLogs, totalCount };
|
|
} catch (error) {
|
|
console.error("Error parsing rawConfig:", error);
|
|
throw new Error("Failed to parse rawConfig");
|
|
}
|
|
}
|
|
|
|
const isStatusInRange = (status: number, range: string) => {
|
|
switch (range) {
|
|
case "info":
|
|
return status >= 100 && status <= 199;
|
|
case "success":
|
|
return status >= 200 && status <= 299;
|
|
case "redirect":
|
|
return status >= 300 && status <= 399;
|
|
case "client":
|
|
return status >= 400 && status <= 499;
|
|
case "server":
|
|
return status >= 500 && status <= 599;
|
|
default:
|
|
return false;
|
|
}
|
|
};
|