feat(日志): 添加定时修剪项目控制台日志功能
实现每小时自动修剪项目控制台日志列表至1000条的功能 新增日志修剪工具函数和相应测试用例 在服务器关闭时清理日志修剪定时器
This commit is contained in:
@@ -3,6 +3,7 @@ import request from 'supertest';
|
||||
|
||||
import { createApp } from '../app.js';
|
||||
import { createFakeRedis } from '../test/fakeRedis.js';
|
||||
import { trimProjectConsoleLogsByLength } from './logs.js';
|
||||
|
||||
describe('projects API', () => {
|
||||
it('GET /api/projects returns projects from unified list', async () => {
|
||||
@@ -95,6 +96,24 @@ describe('projects API', () => {
|
||||
});
|
||||
|
||||
describe('logs API', () => {
|
||||
it('trimProjectConsoleLogsByLength trims *_项目控制台 lists to 1000 items', async () => {
|
||||
const projectName = 'Demo';
|
||||
const key = `${projectName}_项目控制台`;
|
||||
const items = Array.from({ length: 1505 }, (_, i) => `l${i + 1}`);
|
||||
const redis = createFakeRedis({
|
||||
[key]: items,
|
||||
other: [ 'x', 'y' ],
|
||||
});
|
||||
|
||||
const result = await trimProjectConsoleLogsByLength(redis, { maxLen: 1000 });
|
||||
expect(result).toMatchObject({ keysScanned: 1, keysTrimmed: 1, maxLen: 1000 });
|
||||
|
||||
const listItems = await redis.lRange(key, 0, -1);
|
||||
expect(listItems.length).toBe(1000);
|
||||
expect(listItems[0]).toBe('l506');
|
||||
expect(listItems[listItems.length - 1]).toBe('l1505');
|
||||
});
|
||||
|
||||
it('GET /api/logs uses LOG_TTL_MS=24h without wiping recent logs', async () => {
|
||||
const prev = process.env.LOG_TTL_MS;
|
||||
process.env.LOG_TTL_MS = '24h';
|
||||
@@ -202,6 +221,38 @@ describe('logs API', () => {
|
||||
expect(JSON.parse(listItems[0]).id).toBe('new');
|
||||
});
|
||||
|
||||
it('GET /api/logs keeps latest 1000 logs when all timestamps are expired', async () => {
|
||||
const now = Date.now();
|
||||
const projectName = 'Demo';
|
||||
const key = `${projectName}_项目控制台`;
|
||||
const items = Array.from({ length: 1505 }, (_, i) =>
|
||||
JSON.stringify({
|
||||
id: `log-${i + 1}`,
|
||||
timestamp: new Date(now - 26 * 60 * 60 * 1000).toISOString(),
|
||||
level: 'info',
|
||||
message: `m${i + 1}`,
|
||||
}),
|
||||
);
|
||||
const redis = createFakeRedis({
|
||||
[key]: items,
|
||||
});
|
||||
|
||||
const app = createApp({ redis });
|
||||
const resp = await request(app)
|
||||
.get('/api/logs')
|
||||
.query({ projectName, limit: 1000 });
|
||||
|
||||
expect(resp.status).toBe(200);
|
||||
expect(resp.body.logs.length).toBe(1000);
|
||||
expect(resp.body.logs[0].id).toBe('log-506');
|
||||
expect(resp.body.logs[resp.body.logs.length - 1].id).toBe('log-1505');
|
||||
|
||||
const listItems = await redis.lRange(key, 0, -1);
|
||||
expect(listItems.length).toBe(1000);
|
||||
expect(JSON.parse(listItems[0]).id).toBe('log-506');
|
||||
expect(JSON.parse(listItems[listItems.length - 1]).id).toBe('log-1505');
|
||||
});
|
||||
|
||||
it('GET /api/logs keeps unix-second timestamps and prunes correctly', async () => {
|
||||
const now = Date.now();
|
||||
const nowSec = Math.floor(now / 1000);
|
||||
|
||||
Reference in New Issue
Block a user