new file: src/pages/api/log.ts new file: src/pages/log.tsx modified: tsconfig.jsonmaster
parent
04ca57a2aa
commit
021680325e
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,45 @@ |
||||
import fs from 'fs'; |
||||
import type { NextApiRequest, NextApiResponse } from 'next'; |
||||
|
||||
// Путь к лог-файлу доступа Nginx
|
||||
const logFilePath = '@../../log/access_blogbaster.log'; |
||||
|
||||
let log: string[] = []; |
||||
|
||||
export default function handler( |
||||
req: NextApiRequest, |
||||
res: NextApiResponse |
||||
) { |
||||
// Чтение лог-файла
|
||||
fs.readFile(logFilePath, 'utf8', (err, data) => { |
||||
if (err) throw err; |
||||
|
||||
// Разбиваем содержимое файла на строки
|
||||
const logLines = data.split('\n'); |
||||
|
||||
// Объект для хранения статистики
|
||||
const mp3Stats: { [key: string]: number } = {}; |
||||
|
||||
// Анализируем каждую строку лога
|
||||
logLines.forEach((line) => { |
||||
// Проверяем, содержит ли строка запрос к mp3 файлу
|
||||
if (line.includes('.mp3')) { |
||||
const fileName = line.match(/\/([^/]+\.mp3)/)?.[1]; |
||||
if (fileName) { |
||||
if (mp3Stats[fileName]) { |
||||
mp3Stats[fileName]++; |
||||
} else { |
||||
mp3Stats[fileName] = 1; |
||||
} |
||||
} |
||||
} |
||||
}); |
||||
|
||||
// Выводим статистику
|
||||
for (const fileName in mp3Stats) { |
||||
log.push(fileName + ',' + mp3Stats[fileName]); |
||||
} |
||||
//let logData = JSON.stringify(log);
|
||||
res.status(200).json(log); |
||||
}); |
||||
} |
@ -0,0 +1,57 @@ |
||||
import React, { useState, useEffect } from 'react'; |
||||
|
||||
type LogData = { |
||||
fileName: string; |
||||
accessCount: number; |
||||
}; |
||||
|
||||
const LogTable: React.FC = () => { |
||||
const [logData, setLogData] = useState<LogData[]>([]); |
||||
|
||||
useEffect(() => { |
||||
fetch('/api/log') // Обращаемся к REST API
|
||||
.then((response) => response.json()) |
||||
.then((data: string[]) => { |
||||
const parsedData: LogData[] = data.map((item: string) => { |
||||
const [fileName, accessCountStr] = item.split(","); |
||||
const accessCount: number = parseInt(accessCountStr); |
||||
return { fileName, accessCount }; |
||||
}); |
||||
setLogData(parsedData); |
||||
}); |
||||
}, []); |
||||
|
||||
return ( |
||||
<div className="m-3 card lg:card-side bg-base-100 shadow-xl"> |
||||
<div className="flex flex-col items-center bg-white border border-gray-200 rounded-lg shadow md:flex-row "> |
||||
<div className="mb-3 object-cover rounded-t-lg md:w-auto md:min-w-64 md:max-w-64 md:rounded-s-lg md:m-3"> |
||||
<div> |
||||
<h2>Статистика доступа к mp3 файлам</h2> |
||||
<div className="container mx-auto p-6"> |
||||
<table className="min-w-full bg-white border border-gray-300"> |
||||
<thead> |
||||
<tr> |
||||
<th className="py-2 px-4 border-b">№</th> |
||||
<th className="py-2 px-4 border-b">Имя файла</th> |
||||
<th className="py-2 px-4 border-b">Количество доступов</th> |
||||
</tr> |
||||
</thead> |
||||
<tbody> |
||||
{logData.map((item, index) => ( |
||||
<tr key={index}> |
||||
<td className="py-2 px-4 border-b">{index + 1}</td> |
||||
<td className="py-2 px-4 border-b">{item.fileName}</td> |
||||
<td className="py-2 px-4 border-b">{item.accessCount}</td> |
||||
</tr> |
||||
))} |
||||
</tbody> |
||||
</table> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
); |
||||
}; |
||||
|
||||
export default LogTable; |
Loading…
Reference in new issue