mirror of
https://github.com/jeffusion/gitea-ai-assistant.git
synced 2026-03-27 10:05:50 +00:00
refactor(logger): migrate to pino with global LOG_LEVEL control
Replace custom console-based logger with pino backend supporting LOG_LEVEL environment variable. - Add pino dependency for structured JSON logging - Implement LOG_LEVEL env var support (debug/info/warn/error, default: info) - Remove REPO_LIST_DEBUG_LOGS special flag in favor of global LOG_LEVEL - Preserve existing logger API compatibility (message, meta?) - Add safe error serialization to prevent credential leakage Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
This commit is contained in:
@@ -9,7 +9,6 @@ import { logger } from '../utils/logger';
|
|||||||
|
|
||||||
const publicRoutes = new Hono();
|
const publicRoutes = new Hono();
|
||||||
const protectedRoutes = new Hono();
|
const protectedRoutes = new Hono();
|
||||||
const isRepoListDebugEnabled = process.env.REPO_LIST_DEBUG_LOGS === 'true';
|
|
||||||
|
|
||||||
// --- Public Routes ---
|
// --- Public Routes ---
|
||||||
|
|
||||||
@@ -48,33 +47,27 @@ protectedRoutes.get('/repositories', async (c) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (isRepoListDebugEnabled) {
|
logger.debug('开始获取仓库列表', requestContext);
|
||||||
logger.debug('开始获取仓库列表', requestContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
const { repos, totalCount } = await giteaService.listAllRepositories(page, limit, query);
|
const { repos, totalCount } = await giteaService.listAllRepositories(page, limit, query);
|
||||||
if (isRepoListDebugEnabled) {
|
logger.debug('仓库搜索接口返回成功', {
|
||||||
logger.debug('仓库搜索接口返回成功', {
|
...requestContext,
|
||||||
...requestContext,
|
reposCount: repos.length,
|
||||||
reposCount: repos.length,
|
totalCount,
|
||||||
totalCount,
|
sampleRepos: repos
|
||||||
sampleRepos: repos
|
.slice(0, 3)
|
||||||
.slice(0, 3)
|
.map((repo) => (typeof repo.full_name === 'string' ? repo.full_name : null)),
|
||||||
.map((repo) => (typeof repo.full_name === 'string' ? repo.full_name : null)),
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const webhookUrl = c.req.url.replace(/\/admin\/api\/repositories.*$/, '/webhook/gitea');
|
const webhookUrl = c.req.url.replace(/\/admin\/api\/repositories.*$/, '/webhook/gitea');
|
||||||
const fullNames = repos
|
const fullNames = repos
|
||||||
.map((repo) => (typeof repo.full_name === 'string' ? repo.full_name : null))
|
.map((repo) => (typeof repo.full_name === 'string' ? repo.full_name : null))
|
||||||
.filter((name): name is string => name !== null);
|
.filter((name): name is string => name !== null);
|
||||||
if (isRepoListDebugEnabled) {
|
logger.debug('准备批量读取项目级提示词', {
|
||||||
logger.debug('准备批量读取项目级提示词', {
|
...requestContext,
|
||||||
...requestContext,
|
fullNamesCount: fullNames.length,
|
||||||
fullNamesCount: fullNames.length,
|
fullNamesSample: fullNames.slice(0, 5),
|
||||||
fullNamesSample: fullNames.slice(0, 5),
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let promptMap: Record<string, string>;
|
let promptMap: Record<string, string>;
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -3,8 +3,6 @@ import config from '../config';
|
|||||||
import { toErrorLogMeta } from '../utils/error-log';
|
import { toErrorLogMeta } from '../utils/error-log';
|
||||||
import { logger } from '../utils/logger';
|
import { logger } from '../utils/logger';
|
||||||
|
|
||||||
const isRepoListDebugEnabled = process.env.REPO_LIST_DEBUG_LOGS === 'true';
|
|
||||||
|
|
||||||
export interface LineComment {
|
export interface LineComment {
|
||||||
path: string;
|
path: string;
|
||||||
line: number;
|
line: number;
|
||||||
@@ -426,9 +424,7 @@ export const giteaService: GiteaService = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (isRepoListDebugEnabled) {
|
logger.debug('开始请求 Gitea 仓库搜索接口', requestContext);
|
||||||
logger.debug('开始请求 Gitea 仓库搜索接口', requestContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await giteaAdminClient.get('/repos/search', {
|
const response = await giteaAdminClient.get('/repos/search', {
|
||||||
params: {
|
params: {
|
||||||
@@ -438,15 +434,13 @@ export const giteaService: GiteaService = {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (isRepoListDebugEnabled) {
|
logger.debug('Gitea 仓库搜索接口返回成功', {
|
||||||
logger.debug('Gitea 仓库搜索接口返回成功', {
|
...requestContext,
|
||||||
...requestContext,
|
status: response.status,
|
||||||
status: response.status,
|
contentType: response.headers['content-type'] ?? null,
|
||||||
contentType: response.headers['content-type'] ?? null,
|
dataCount: Array.isArray(response.data?.data) ? response.data.data.length : null,
|
||||||
dataCount: Array.isArray(response.data?.data) ? response.data.data.length : null,
|
headerTotalCount: response.headers['x-total-count'] ?? null,
|
||||||
headerTotalCount: response.headers['x-total-count'] ?? null,
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const totalCount = Number.parseInt(response.headers['x-total-count'] || '0', 10);
|
const totalCount = Number.parseInt(response.headers['x-total-count'] || '0', 10);
|
||||||
return { repos: response.data.data, totalCount };
|
return { repos: response.data.data, totalCount };
|
||||||
|
|||||||
@@ -1,58 +1,90 @@
|
|||||||
// 简单的日志实用工具
|
import pino from 'pino';
|
||||||
|
|
||||||
/**
|
|
||||||
* 日志级别
|
|
||||||
*/
|
|
||||||
export enum LogLevel {
|
export enum LogLevel {
|
||||||
DEBUG = 'DEBUG',
|
DEBUG = 'debug',
|
||||||
INFO = 'INFO',
|
INFO = 'info',
|
||||||
WARN = 'WARN',
|
WARN = 'warn',
|
||||||
ERROR = 'ERROR',
|
ERROR = 'error',
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
type LogMeta = Record<string, unknown>;
|
||||||
* 格式化时间
|
type ErrorWithCode = Error & { code?: unknown };
|
||||||
*/
|
|
||||||
function formatTime(): string {
|
|
||||||
return new Date().toISOString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
function resolveLogLevel(rawLevel: string | undefined): LogLevel {
|
||||||
* 格式化日志消息
|
if (!rawLevel) {
|
||||||
*/
|
return LogLevel.INFO;
|
||||||
function formatMessage(level: LogLevel, message: string, meta?: any): string {
|
|
||||||
const timestamp = formatTime();
|
|
||||||
|
|
||||||
let formattedMessage = `[${timestamp}] [${level}] ${message}`;
|
|
||||||
|
|
||||||
if (meta) {
|
|
||||||
try {
|
|
||||||
formattedMessage += ` - ${JSON.stringify(meta)}`;
|
|
||||||
} catch (_error) {
|
|
||||||
formattedMessage += ` - ${meta}`;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return formattedMessage;
|
const normalized = rawLevel.toLowerCase();
|
||||||
|
if (normalized === LogLevel.DEBUG) return LogLevel.DEBUG;
|
||||||
|
if (normalized === LogLevel.INFO) return LogLevel.INFO;
|
||||||
|
if (normalized === LogLevel.WARN) return LogLevel.WARN;
|
||||||
|
if (normalized === LogLevel.ERROR) return LogLevel.ERROR;
|
||||||
|
return LogLevel.INFO;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toLogMeta(meta: unknown): LogMeta | undefined {
|
||||||
|
if (meta === undefined) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (meta instanceof Error) {
|
||||||
|
const maybeCode = (meta as ErrorWithCode).code;
|
||||||
|
const code =
|
||||||
|
typeof maybeCode === 'string' || typeof maybeCode === 'number' ? maybeCode : undefined;
|
||||||
|
|
||||||
|
return {
|
||||||
|
error: {
|
||||||
|
name: meta.name,
|
||||||
|
message: meta.message,
|
||||||
|
stack: meta.stack,
|
||||||
|
...(code !== undefined ? { code } : {}),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof meta === 'object' && meta !== null) {
|
||||||
|
return meta as LogMeta;
|
||||||
|
}
|
||||||
|
|
||||||
|
return { meta };
|
||||||
|
}
|
||||||
|
|
||||||
|
const baseLogger = pino({
|
||||||
|
level: resolveLogLevel(process.env.LOG_LEVEL),
|
||||||
|
base: null,
|
||||||
|
timestamp: pino.stdTimeFunctions.isoTime,
|
||||||
|
formatters: {
|
||||||
|
level(label) {
|
||||||
|
return { level: label.toUpperCase() };
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
function writeLog(level: LogLevel, message: string, meta?: unknown): void {
|
||||||
|
const logMeta = toLogMeta(meta);
|
||||||
|
if (logMeta) {
|
||||||
|
baseLogger[level](logMeta, message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
baseLogger[level](message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 日志实用工具
|
|
||||||
*/
|
|
||||||
export const logger = {
|
export const logger = {
|
||||||
debug(message: string, meta?: any) {
|
debug(message: string, meta?: unknown): void {
|
||||||
console.debug(formatMessage(LogLevel.DEBUG, message, meta));
|
writeLog(LogLevel.DEBUG, message, meta);
|
||||||
},
|
},
|
||||||
|
|
||||||
info(message: string, meta?: any) {
|
info(message: string, meta?: unknown): void {
|
||||||
console.info(formatMessage(LogLevel.INFO, message, meta));
|
writeLog(LogLevel.INFO, message, meta);
|
||||||
},
|
},
|
||||||
|
|
||||||
warn(message: string, meta?: any) {
|
warn(message: string, meta?: unknown): void {
|
||||||
console.warn(formatMessage(LogLevel.WARN, message, meta));
|
writeLog(LogLevel.WARN, message, meta);
|
||||||
},
|
},
|
||||||
|
|
||||||
error(message: string, meta?: any) {
|
error(message: string, meta?: unknown): void {
|
||||||
console.error(formatMessage(LogLevel.ERROR, message, meta));
|
writeLog(LogLevel.ERROR, message, meta);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user