@xiaoyue9527/audit-log-client
v1.0.0
Published
TypeScript/JavaScript client for audit logging services
Maintainers
Readme
审计日志客户端 (Audit Log Client) - TypeScript/JavaScript
用于审计日志服务的 TypeScript/JavaScript 客户端库,支持同步和异步两种使用模式。提供自动缓冲、批量发送、重试机制和降级策略,确保审计日志的可靠记录。
✨ 主要特性
- 🚀 双模式支持:同步和异步 API,适应不同应用场景
- 📦 智能缓冲:自动缓冲日志,批量发送,提高性能
- 🔄 自动重试:指数退避重试策略,提高可靠性
- 💾 降级策略:网络失败时自动写入本地文件,确保日志不丢失
- 🔍 灵活查询:支持多维度条件查询审计日志
- 🔒 安全认证:基于 AppID 和 SecretKey 的应用级认证
- 📊 类型安全:完整的 TypeScript 类型定义
- 🌐 框架支持:支持 Node.js、Express、Fastify、NestJS 等
📦 安装
npm install audit-log-client
# 或
yarn add audit-log-client
# 或
pnpm add audit-log-client依赖要求
- Node.js >= 14.0.0
- TypeScript >= 5.0.0 (可选,但推荐)
🚀 快速开始
同步客户端
import {
SyncAuditLogClient,
AuditLog,
AuditAction,
AuditTarget,
} from "audit-log-client";
// 初始化客户端
const client = new SyncAuditLogClient({
base_url: "http://audit.service/api",
app_id: "your-app-id",
secret_key: "your-secret-key",
});
// 创建审计日志
const log: AuditLog = {
action: AuditAction.UPDATE,
target_type: AuditTarget.USER,
user_id: "admin",
description: "用户资料更新",
target_id: "user123",
ip_address: "192.168.1.1",
before: { name: "张三" },
after: { name: "张三丰" },
};
// 记录日志(自动缓冲,批量发送)
client.log(log);
// 重要:程序退出前关闭客户端,确保缓冲区刷新
await client.close();异步客户端
import {
AsyncAuditLogClient,
AuditLog,
AuditAction,
AuditTarget,
} from "audit-log-client";
async function main() {
// 初始化客户端
const client = new AsyncAuditLogClient({
base_url: "http://audit.service/api",
app_id: "your-app-id",
secret_key: "your-secret-key",
});
// 重要:异步客户端需要先初始化,启动后台刷新任务
await client.initialize();
// 创建审计日志
const log: AuditLog = {
action: AuditAction.CREATE,
target_type: AuditTarget.ORDER,
user_id: "sales",
description: "新建订单",
target_id: "order456",
};
// 记录日志
await client.log(log);
// 重要:关闭客户端,确保缓冲区刷新
await client.shutdown();
}
main();⚙️ 配置选项
客户端初始化参数
interface ClientOptions {
base_url: string; // 服务地址(必需)
app_id: string; // 应用ID(必需)
secret_key: string; // 应用密钥(必需)
buffer_size?: number; // 缓冲区大小,默认100
flush_interval?: number; // 刷新间隔(秒),默认10
max_retries?: number; // 最大重试次数,默认3
timeout?: number; // 请求超时(毫秒),默认10000
}缓冲机制说明
自动刷新触发条件:
- 缓冲区达到
buffer_size时立即刷新 - 每隔
flush_interval秒自动刷新 - 调用
close()或shutdown()时执行最终刷新
- 缓冲区达到
推荐配置:
- 高频场景:
buffer_size: 500, flush_interval: 5(更频繁发送) - 低频场景:
buffer_size: 50, flush_interval: 30(减少请求) - 实时性要求高:
buffer_size: 10, flush_interval: 2(快速发送)
- 高频场景:
📝 使用示例
批量记录日志
// 同步客户端
const logs: AuditLog[] = Array.from({ length: 100 }, (_, i) => ({
action: AuditAction.CREATE,
target_type: AuditTarget.USER,
user_id: "admin",
description: `创建用户 ${i}`,
}));
client.batchLog(logs);
// 异步客户端
await client.batchLog(logs);查询审计日志
import { AuditLogFilter } from "audit-log-client";
// 查询最近1小时的用户更新日志
const endTime = new Date();
const startTime = new Date(endTime.getTime() - 60 * 60 * 1000);
const filter: AuditLogFilter = {
action: "UPDATE",
target_type: "USER",
user_id: "admin",
start_time: startTime,
end_time: endTime,
limit: 100,
};
const logs = await client.queryLogs(filter);
logs.forEach((log) => {
console.log(`${log.timestamp}: ${log.description}`);
});在 Express 应用中使用
import express from "express";
import {
SyncAuditLogClient,
AuditLog,
AuditAction,
AuditTarget,
} from "audit-log-client";
const app = express();
app.use(express.json());
// 全局客户端实例
const auditClient = new SyncAuditLogClient({
base_url: process.env.AUDIT_SERVICE_URL!,
app_id: process.env.AUDIT_APP_ID!,
secret_key: process.env.AUDIT_SECRET_KEY!,
});
app.put("/users/:userId", async (req, res) => {
// 业务逻辑...
// 记录审计日志
auditClient.log({
action: AuditAction.UPDATE,
target_type: AuditTarget.USER,
user_id: req.user.id,
target_id: req.params.userId,
description: `更新用户 ${req.params.userId}`,
ip_address: req.ip,
before: { status: "active" },
after: { status: "inactive" },
});
res.json({ status: "ok" });
});
// 应用关闭时清理
process.on("SIGTERM", async () => {
await auditClient.close();
process.exit(0);
});在 Fastify 应用中使用
import Fastify from "fastify";
import {
AsyncAuditLogClient,
AuditLog,
AuditAction,
AuditTarget,
} from "audit-log-client";
const fastify = Fastify();
// 全局客户端实例
let auditClient: AsyncAuditLogClient;
fastify.addHook("onReady", async () => {
auditClient = new AsyncAuditLogClient({
base_url: process.env.AUDIT_SERVICE_URL!,
app_id: process.env.AUDIT_APP_ID!,
secret_key: process.env.AUDIT_SECRET_KEY!,
});
await auditClient.initialize();
});
fastify.addHook("onClose", async () => {
if (auditClient) {
await auditClient.shutdown();
}
});
fastify.put("/users/:userId", async (request, reply) => {
// 业务逻辑...
// 记录审计日志
await auditClient.log({
action: AuditAction.UPDATE,
target_type: AuditTarget.USER,
user_id: request.user.id,
target_id: request.params.userId,
description: `更新用户 ${request.params.userId}`,
});
return { status: "ok" };
});在 NestJS 应用中使用
// audit-log.service.ts
import { Injectable, OnModuleInit, OnModuleDestroy } from "@nestjs/common";
import {
AsyncAuditLogClient,
AuditLog,
AuditAction,
AuditTarget,
} from "audit-log-client";
@Injectable()
export class AuditLogService implements OnModuleInit, OnModuleDestroy {
private client: AsyncAuditLogClient;
async onModuleInit() {
this.client = new AsyncAuditLogClient({
base_url: process.env.AUDIT_SERVICE_URL!,
app_id: process.env.AUDIT_APP_ID!,
secret_key: process.env.AUDIT_SECRET_KEY!,
});
await this.client.initialize();
}
async onModuleDestroy() {
if (this.client) {
await this.client.shutdown();
}
}
async log(log: AuditLog): Promise<void> {
await this.client.log(log);
}
}
// user.controller.ts
import { Controller, Put, Param } from "@nestjs/common";
import { AuditLogService } from "./audit-log.service";
import { AuditAction, AuditTarget } from "audit-log-client";
@Controller("users")
export class UserController {
constructor(private readonly auditLogService: AuditLogService) {}
@Put(":id")
async updateUser(@Param("id") id: string) {
// 业务逻辑...
await this.auditLogService.log({
action: AuditAction.UPDATE,
target_type: AuditTarget.USER,
user_id: "current_user",
target_id: id,
description: `更新用户 ${id}`,
});
}
}🔐 认证方式
客户端使用 AppID + SecretKey 进行身份验证:
- 获取凭证:从审计日志服务管理员处获取应用的
app_id和secret_key - 配置客户端:初始化时传入凭证
- 自动认证:客户端自动在请求头中添加认证信息
// 推荐:使用环境变量管理密钥
const client = new SyncAuditLogClient({
base_url: process.env.AUDIT_SERVICE_URL!,
app_id: process.env.AUDIT_APP_ID!,
secret_key: process.env.AUDIT_SECRET_KEY!, // 不要硬编码密钥!
});🛡️ 错误处理和降级策略
自动重试机制
客户端内置指数退避重试机制:
- 默认重试 3 次
- 重试间隔:1秒 → 2秒 → 4秒
- 可配置
max_retries参数
降级到本地文件
当所有重试失败后,日志会自动写入本地文件 audit_fallback.log(JSON Lines 格式):
// 降级文件位置:当前工作目录下的 audit_fallback.log
// 格式:每行一个 JSON 对象处理降级文件:
import * as fs from "fs";
import * as readline from "readline";
import { AuditLog } from "audit-log-client";
// 读取降级日志并重新发送
const fileStream = fs.createReadStream("audit_fallback.log");
const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity,
});
for await (const line of rl) {
const logData: AuditLog = JSON.parse(line);
await client.log(logData); // 重新发送
}
// 清空已处理的日志
fs.writeFileSync("audit_fallback.log", "");错误处理示例
try {
client.log(log);
} catch (error) {
// 客户端内部已处理重试和降级
// 这里可以记录监控指标或告警
console.error(`Failed to send audit log: ${error}`);
// 日志已写入降级文件,不会丢失
}📊 支持的审计操作类型
基础操作
CREATE, UPDATE, DELETE, LOGIN, LOGOUT, ACCESS, DOWNLOAD, UPLOAD, APPROVE, REJECT, EXPORT, IMPORT, EXECUTE, GRANT, REVOKE
项目管理
RESTORE, CHANGE_STATUS, ADD_MEMBER, UPDATE_MEMBER_ROLE, REMOVE_MEMBER
文件管理
RENAME_FILE, MOVE_FILE, SHARE_FILE, REVOKE_FILE_SHARE
任务管理
CREATE_TASK, ASSIGN_TASK, COMPLETE_TASK, REOPEN_TASK, CHANGE_TASK_PRIORITY, ADD_TASK_COMMENT
支付管理
INITIATE_PAYMENT, PROCESS_PAYMENT, REFUND_PAYMENT, CANCEL_PAYMENT, CREATE_INVOICE, VERIFY_PAYMENT
系统管理
CHANGE_ROLE, UPDATE_PERMISSION, RESET_PASSWORD, LOCK_ACCOUNT, UNLOCK_ACCOUNT
更多操作类型请参考 AuditAction 枚举。
🎯 支持的目标类型
基础实体
USER, FILE, ROLE, PERMISSION, CONFIG, SETTING, PRODUCT, ORDER, CUSTOMER, SESSION, API_KEY, DATABASE, REPORT, PAYMENT
网关和追踪
API, GATEWAY, TRACE, ENDPOINT, ROUTER
业务实体
PROJECT, PROJECT_MEMBER, APPLICATION, FOLDER, SHARED_FILE, TASK, TASK_COMMENT, NOTIFICATION, INVOICE, REFUND, ACCOUNT, DATA_REPORT, DASHBOARD
更多目标类型请参考 AuditTarget 枚举。
💡 最佳实践
1. 资源管理
同步客户端:
const client = new SyncAuditLogClient({...});
try {
// 使用客户端
client.log(log);
} finally {
await client.close(); // 确保刷新缓冲区
}异步客户端:
const client = new AsyncAuditLogClient({...});
try {
await client.initialize();
await client.log(log);
} finally {
await client.shutdown(); // 确保刷新缓冲区
}2. 配置管理
// 推荐:使用环境变量或配置文件
const config = {
base_url: process.env.AUDIT_SERVICE_URL || "http://localhost:8080",
app_id: process.env.AUDIT_APP_ID!,
secret_key: process.env.AUDIT_SECRET_KEY!,
buffer_size: parseInt(process.env.AUDIT_BUFFER_SIZE || "100"),
flush_interval: parseInt(process.env.AUDIT_FLUSH_INTERVAL || "10"),
};
const client = new SyncAuditLogClient(config);3. 性能优化
- 高频场景:增大
buffer_size,减少网络请求 - 低延迟要求:减小
buffer_size和flush_interval - 批量操作:使用
batchLog()而不是多次调用log()
4. 监控和告警
import * as fs from "fs";
// 监控降级文件大小
const fallbackSize = fs.statSync("audit_fallback.log").size;
if (fallbackSize > 10 * 1024 * 1024) {
// 发送告警
console.warn("Audit log fallback file too large");
}🔧 故障排查
问题:日志没有发送
检查项:
- 确认调用了
close()或shutdown() - 检查
audit_fallback.log文件 - 查看控制台日志输出
- 验证网络连接和服务地址
问题:认证失败
检查项:
- 确认
app_id和secret_key正确 - 检查服务端配置中是否包含该应用
- 查看服务端日志
问题:查询返回空结果
检查项:
- 确认时间范围正确
- 检查查询条件是否匹配
- 验证服务端是否有数据
📚 API 参考
SyncAuditLogClient
log(log: AuditLog): void- 记录单条日志batchLog(logs: AuditLog[]): void- 批量记录日志flush(): Promise<boolean>- 手动刷新缓冲区queryLogs(filter: AuditLogFilter): Promise<AuditLog[]>- 查询日志close(): Promise<void>- 关闭客户端并刷新缓冲区
AsyncAuditLogClient
initialize(): Promise<void>- 初始化客户端(必须调用)log(log: AuditLog): Promise<boolean>- 异步记录单条日志batchLog(logs: AuditLog[]): Promise<boolean>- 异步批量记录日志flushAsync(): Promise<boolean>- 异步刷新缓冲区queryLogs(filter: AuditLogFilter): Promise<AuditLog[]>- 异步查询日志shutdown(): Promise<void>- 关闭客户端并刷新缓冲区
AuditLog 接口
interface AuditLog {
action: AuditAction | string; // 操作类型(必需)
target_type: AuditTarget | string; // 目标类型(必需)
user_id: string; // 用户ID(必需)
description: string; // 描述(必需)
target_id?: string; // 目标ID
ip_address?: string; // IP地址
before?: Record<string, any>; // 变更前数据
after?: Record<string, any>; // 变更后数据
timestamp?: Date | string; // 时间戳(默认当前时间)
user_agent?: string; // 用户代理
request_path?: string; // 请求路径
method?: string; // HTTP方法
status_code?: number; // 状态码
parameters?: Record<string, any>; // 参数
metadata?: Record<string, any>; // 元数据
id?: string; // 日志ID(服务端生成)
}🛠️ 开发
构建
npm run build测试
npm test代码检查
npm run lint格式化
npm run format📄 许可证
MIT License
🤝 贡献
欢迎提交 Issue 和 Pull Request!
📞 支持
- 文档:项目文档
- 问题反馈:GitHub Issues
注意:生产环境使用前,请确保:
- ✅ 使用环境变量管理敏感信息(SecretKey)
- ✅ 配置合适的缓冲参数
- ✅ 监控降级文件大小
- ✅ 定期处理降级日志文件
