@jiangnian520/midway-operation-log 0.0.0-stage → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,5 @@
1
+ import type { OperationLogConfig } from '../interface';
2
+ declare const _default: {
3
+ operationLog: OperationLogConfig;
4
+ };
5
+ export default _default;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = {
4
+ operationLog: {
5
+ enable: true,
6
+ useRedis: false,
7
+ redisQueueName: 'operation-log',
8
+ writeLog: async (ctx, logData) => {
9
+ console.log(`[OperationLog] ${logData.methodName} | ${logData.costTime}ms`, logData);
10
+ },
11
+ },
12
+ };
13
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlnLmRlZmF1bHQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY29uZmlnL2NvbmZpZy5kZWZhdWx0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBRUEsa0JBQWU7SUFDYixZQUFZLEVBQUU7UUFDWixNQUFNLEVBQUUsSUFBSTtRQUNaLFFBQVEsRUFBRSxLQUFLO1FBQ2YsY0FBYyxFQUFFLGVBQWU7UUFDL0IsUUFBUSxFQUFFLEtBQUssRUFBRSxHQUFHLEVBQUUsT0FBTyxFQUFFLEVBQUU7WUFDL0IsT0FBTyxDQUFDLEdBQUcsQ0FBQyxrQkFBa0IsT0FBTyxDQUFDLFVBQVUsTUFBTSxPQUFPLENBQUMsUUFBUSxJQUFJLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFDdkYsQ0FBQztLQUNvQjtDQUN4QixDQUFDIn0=
@@ -0,0 +1,7 @@
1
+ import { MidwayDecoratorService } from '@midwayjs/core';
2
+ import type { ILifeCycle, IMidwayContainer } from '@midwayjs/core';
3
+ export declare class OperationLogConfiguration implements ILifeCycle {
4
+ decoratorService: MidwayDecoratorService;
5
+ applicationContext: IMidwayContainer;
6
+ onReady(): Promise<void>;
7
+ }
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
19
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
20
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
21
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
22
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
23
+ };
24
+ var __importStar = (this && this.__importStar) || (function () {
25
+ var ownKeys = function(o) {
26
+ ownKeys = Object.getOwnPropertyNames || function (o) {
27
+ var ar = [];
28
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
+ return ar;
30
+ };
31
+ return ownKeys(o);
32
+ };
33
+ return function (mod) {
34
+ if (mod && mod.__esModule) return mod;
35
+ var result = {};
36
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
+ __setModuleDefault(result, mod);
38
+ return result;
39
+ };
40
+ })();
41
+ var __metadata = (this && this.__metadata) || function (k, v) {
42
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
43
+ };
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ exports.OperationLogConfiguration = void 0;
46
+ const core_1 = require("@midwayjs/core");
47
+ const DefaultConfig = __importStar(require("./config/config.default"));
48
+ const interface_1 = require("./interface");
49
+ const queue_interface_1 = require("./queue/queue.interface");
50
+ const memory_queue_1 = require("./queue/memory.queue");
51
+ const redis_queue_1 = require("./queue/redis.queue");
52
+ let OperationLogConfiguration = class OperationLogConfiguration {
53
+ async onReady() {
54
+ const configService = this.applicationContext.get(core_1.MidwayConfigService);
55
+ const config = configService.getConfiguration('operationLog');
56
+ if (config.useRedis) {
57
+ this.applicationContext.registerObject(queue_interface_1.LOG_QUEUE_TOKEN, redis_queue_1.RedisLogQueue);
58
+ }
59
+ else {
60
+ this.applicationContext.registerObject(queue_interface_1.LOG_QUEUE_TOKEN, memory_queue_1.MemoryLogQueue);
61
+ }
62
+ this.decoratorService.registerMethodHandler(interface_1.LOGGING_KEY, (options) => {
63
+ return {
64
+ around: async (joinPoint) => {
65
+ const ctx = joinPoint.target[core_1.REQUEST_OBJ_CTX_KEY];
66
+ if (ctx) {
67
+ ctx.state = ctx.state || {};
68
+ ctx.state.__log_meta__ = {
69
+ methodName: joinPoint.methodName,
70
+ options,
71
+ };
72
+ }
73
+ return joinPoint.proceed(...joinPoint.args);
74
+ },
75
+ };
76
+ });
77
+ }
78
+ };
79
+ exports.OperationLogConfiguration = OperationLogConfiguration;
80
+ __decorate([
81
+ (0, core_1.Inject)(),
82
+ __metadata("design:type", core_1.MidwayDecoratorService)
83
+ ], OperationLogConfiguration.prototype, "decoratorService", void 0);
84
+ __decorate([
85
+ (0, core_1.ApplicationContext)(),
86
+ __metadata("design:type", Object)
87
+ ], OperationLogConfiguration.prototype, "applicationContext", void 0);
88
+ exports.OperationLogConfiguration = OperationLogConfiguration = __decorate([
89
+ (0, core_1.Configuration)({
90
+ namespace: 'operationLog',
91
+ importConfigs: [{ default: DefaultConfig }],
92
+ })
93
+ ], OperationLogConfiguration);
94
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlndXJhdGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9jb25maWd1cmF0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLHlDQU93QjtBQUV4Qix1RUFBeUQ7QUFDekQsMkNBQTBDO0FBQzFDLDZEQUEwRDtBQUMxRCx1REFBc0Q7QUFDdEQscURBQW9EO0FBTTdDLElBQU0seUJBQXlCLEdBQS9CLE1BQU0seUJBQXlCO0lBT3BDLEtBQUssQ0FBQyxPQUFPO1FBQ1gsTUFBTSxhQUFhLEdBQUcsSUFBSSxDQUFDLGtCQUFrQixDQUFDLEdBQUcsQ0FBQywwQkFBbUIsQ0FBQyxDQUFDO1FBQ3ZFLE1BQU0sTUFBTSxHQUFHLGFBQWEsQ0FBQyxnQkFBZ0IsQ0FBQyxjQUFjLENBQUMsQ0FBQztRQUU5RCxJQUFJLE1BQU0sQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUNwQixJQUFJLENBQUMsa0JBQWtCLENBQUMsY0FBYyxDQUFDLGlDQUFlLEVBQUUsMkJBQWEsQ0FBQyxDQUFDO1FBQ3pFLENBQUM7YUFBTSxDQUFDO1lBQ04sSUFBSSxDQUFDLGtCQUFrQixDQUFDLGNBQWMsQ0FBQyxpQ0FBZSxFQUFFLDZCQUFjLENBQUMsQ0FBQztRQUMxRSxDQUFDO1FBRUQsSUFBSSxDQUFDLGdCQUFnQixDQUFDLHFCQUFxQixDQUFDLHVCQUFXLEVBQUUsQ0FBQyxPQUFPLEVBQUUsRUFBRTtZQUNuRSxPQUFPO2dCQUNMLE1BQU0sRUFBRSxLQUFLLEVBQUUsU0FBUyxFQUFFLEVBQUU7b0JBQzFCLE1BQU0sR0FBRyxHQUFHLFNBQVMsQ0FBQyxNQUFNLENBQUMsMEJBQW1CLENBQUMsQ0FBQztvQkFFbEQsSUFBSSxHQUFHLEVBQUUsQ0FBQzt3QkFDUixHQUFHLENBQUMsS0FBSyxHQUFHLEdBQUcsQ0FBQyxLQUFLLElBQUksRUFBRSxDQUFDO3dCQUM1QixHQUFHLENBQUMsS0FBSyxDQUFDLFlBQVksR0FBRzs0QkFDdkIsVUFBVSxFQUFFLFNBQVMsQ0FBQyxVQUFVOzRCQUNoQyxPQUFPO3lCQUNSLENBQUM7b0JBQ0osQ0FBQztvQkFFRCxPQUFPLFNBQVMsQ0FBQyxPQUFRLENBQUMsR0FBRyxTQUFTLENBQUMsSUFBSSxDQUFDLENBQUM7Z0JBQy9DLENBQUM7YUFDRixDQUFDO1FBQ0osQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0NBQ0YsQ0FBQTtBQW5DWSw4REFBeUI7QUFFcEM7SUFEQyxJQUFBLGFBQU0sR0FBRTs4QkFDUyw2QkFBc0I7bUVBQUM7QUFHekM7SUFEQyxJQUFBLHlCQUFrQixHQUFFOztxRUFDZ0I7b0NBTDFCLHlCQUF5QjtJQUpyQyxJQUFBLG9CQUFhLEVBQUM7UUFDYixTQUFTLEVBQUUsY0FBYztRQUN6QixhQUFhLEVBQUUsQ0FBQyxFQUFFLE9BQU8sRUFBRSxhQUFhLEVBQUUsQ0FBQztLQUM1QyxDQUFDO0dBQ1cseUJBQXlCLENBbUNyQyJ9
@@ -0,0 +1,24 @@
1
+ import type { LogOptions } from '../interface';
2
+ /**
3
+ * # 操作日志装饰器
4
+ *
5
+ * 标记在 Controller 的方法上,自动收集请求参数、耗时、响应结果并异步写入日志。
6
+ * 注意:只有在被该装饰器标记的方法,且全局配置了 `writeLog` 的情况下才会生效。
7
+ *
8
+ * @param options 日志记录配置项(标题、业务类型、记录模式等)
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * @Post('/create')
13
+ * @Log({
14
+ * title: '新增物料',
15
+ * businessType: 1,
16
+ * logMode: 'summary',
17
+ * collectSource: ['body', 'query']
18
+ * })
19
+ * async createMaterial(@Body() body: any) {
20
+ * return { code: 200, message: 'success' };
21
+ * }
22
+ * ```
23
+ */
24
+ export declare function Log(options?: LogOptions): MethodDecorator;
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Log = Log;
4
+ const core_1 = require("@midwayjs/core");
5
+ const interface_1 = require("../interface");
6
+ function resolveFileName() {
7
+ const originalPrepare = Error.prepareStackTrace;
8
+ let callSites = [];
9
+ try {
10
+ Error.prepareStackTrace = (_, stack) => stack;
11
+ callSites = new Error().stack;
12
+ }
13
+ catch {
14
+ return 'unknown';
15
+ }
16
+ finally {
17
+ Error.prepareStackTrace = originalPrepare;
18
+ }
19
+ const selfFile = __filename;
20
+ for (const frame of callSites) {
21
+ const file = frame.getFileName();
22
+ if (!file)
23
+ continue;
24
+ if (file === selfFile)
25
+ continue;
26
+ if (file.includes('node_modules'))
27
+ continue;
28
+ if (/[\\/](tslib|@midwayjs)[\\/]/.test(file))
29
+ continue;
30
+ return file;
31
+ }
32
+ return 'unknown';
33
+ }
34
+ /**
35
+ * # 操作日志装饰器
36
+ *
37
+ * 标记在 Controller 的方法上,自动收集请求参数、耗时、响应结果并异步写入日志。
38
+ * 注意:只有在被该装饰器标记的方法,且全局配置了 `writeLog` 的情况下才会生效。
39
+ *
40
+ * @param options 日志记录配置项(标题、业务类型、记录模式等)
41
+ *
42
+ * @example
43
+ * ```typescript
44
+ * @Post('/create')
45
+ * @Log({
46
+ * title: '新增物料',
47
+ * businessType: 1,
48
+ * logMode: 'summary',
49
+ * collectSource: ['body', 'query']
50
+ * })
51
+ * async createMaterial(@Body() body: any) {
52
+ * return { code: 200, message: 'success' };
53
+ * }
54
+ * ```
55
+ */
56
+ function Log(options = {}) {
57
+ const defaultOptions = {
58
+ businessType: 0,
59
+ needLog: true,
60
+ logResult: true,
61
+ logMode: 'summary',
62
+ maxSampleCount: 3,
63
+ maxRawLength: 8000,
64
+ collectSource: ['body', 'query', 'params'],
65
+ ...options,
66
+ };
67
+ return core_1.DecoratorManager.createCustomMethodDecorator(interface_1.LOGGING_KEY, {
68
+ fileName: resolveFileName(),
69
+ log: defaultOptions,
70
+ });
71
+ }
72
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9nLmRlY29yYXRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9kZWNvcmF0b3IvbG9nLmRlY29yYXRvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQWtEQSxrQkFnQkM7QUFsRUQseUNBQWtEO0FBRWxELDRDQUEyQztBQUUzQyxTQUFTLGVBQWU7SUFDcEIsTUFBTSxlQUFlLEdBQUcsS0FBSyxDQUFDLGlCQUFpQixDQUFDO0lBQ2hELElBQUksU0FBUyxHQUFzQixFQUFFLENBQUM7SUFDdEMsSUFBSSxDQUFDO1FBQ0QsS0FBSyxDQUFDLGlCQUFpQixHQUFHLENBQUMsQ0FBQyxFQUFFLEtBQUssRUFBRSxFQUFFLENBQUMsS0FBWSxDQUFDO1FBQ3JELFNBQVMsR0FBRyxJQUFJLEtBQUssRUFBRSxDQUFDLEtBQXFDLENBQUM7SUFDbEUsQ0FBQztJQUFDLE1BQU0sQ0FBQztRQUNMLE9BQU8sU0FBUyxDQUFDO0lBQ3JCLENBQUM7WUFBUyxDQUFDO1FBQ1AsS0FBSyxDQUFDLGlCQUFpQixHQUFHLGVBQWUsQ0FBQztJQUM5QyxDQUFDO0lBRUQsTUFBTSxRQUFRLEdBQUcsVUFBVSxDQUFDO0lBQzVCLEtBQUssTUFBTSxLQUFLLElBQUksU0FBUyxFQUFFLENBQUM7UUFDNUIsTUFBTSxJQUFJLEdBQUcsS0FBSyxDQUFDLFdBQVcsRUFBRSxDQUFDO1FBQ2pDLElBQUksQ0FBQyxJQUFJO1lBQUUsU0FBUztRQUNwQixJQUFJLElBQUksS0FBSyxRQUFRO1lBQUUsU0FBUztRQUNoQyxJQUFJLElBQUksQ0FBQyxRQUFRLENBQUMsY0FBYyxDQUFDO1lBQUUsU0FBUztRQUM1QyxJQUFJLDZCQUE2QixDQUFDLElBQUksQ0FBQyxJQUFJLENBQUM7WUFBRSxTQUFTO1FBQ3ZELE9BQU8sSUFBSSxDQUFDO0lBQ2hCLENBQUM7SUFDRCxPQUFPLFNBQVMsQ0FBQztBQUNyQixDQUFDO0FBRUQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXFCRztBQUNILFNBQWdCLEdBQUcsQ0FBQyxVQUFzQixFQUFFO0lBQ3hDLE1BQU0sY0FBYyxHQUFlO1FBQy9CLFlBQVksRUFBRSxDQUFDO1FBQ2YsT0FBTyxFQUFFLElBQUk7UUFDYixTQUFTLEVBQUUsSUFBSTtRQUNmLE9BQU8sRUFBRSxTQUFTO1FBQ2xCLGNBQWMsRUFBRSxDQUFDO1FBQ2pCLFlBQVksRUFBRSxJQUFJO1FBQ2xCLGFBQWEsRUFBRSxDQUFDLE1BQU0sRUFBRSxPQUFPLEVBQUUsUUFBUSxDQUFDO1FBQzFDLEdBQUcsT0FBTztLQUNiLENBQUM7SUFFRixPQUFPLHVCQUFnQixDQUFDLDJCQUEyQixDQUFDLHVCQUFXLEVBQUU7UUFDN0QsUUFBUSxFQUFFLGVBQWUsRUFBRTtRQUMzQixHQUFHLEVBQUUsY0FBYztLQUN0QixDQUFDLENBQUM7QUFDUCxDQUFDIn0=
@@ -0,0 +1,4 @@
1
+ export { OperationLogConfiguration as Configuration } from './configuration';
2
+ export { Log } from './decorator/log.decorator';
3
+ export { ReportMiddleware } from './middleware/report.middleware';
4
+ export type { LogOptions, CollectedLogData, OperationLogConfig } from './interface';
package/dist/index.js ADDED
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ReportMiddleware = exports.Log = exports.Configuration = void 0;
4
+ var configuration_1 = require("./configuration");
5
+ Object.defineProperty(exports, "Configuration", { enumerable: true, get: function () { return configuration_1.OperationLogConfiguration; } });
6
+ var log_decorator_1 = require("./decorator/log.decorator");
7
+ Object.defineProperty(exports, "Log", { enumerable: true, get: function () { return log_decorator_1.Log; } });
8
+ var report_middleware_1 = require("./middleware/report.middleware");
9
+ Object.defineProperty(exports, "ReportMiddleware", { enumerable: true, get: function () { return report_middleware_1.ReportMiddleware; } });
10
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsaURBQTZFO0FBQXBFLDhHQUFBLHlCQUF5QixPQUFpQjtBQUNuRCwyREFBZ0Q7QUFBdkMsb0dBQUEsR0FBRyxPQUFBO0FBQ1osb0VBQWtFO0FBQXpELHFIQUFBLGdCQUFnQixPQUFBIn0=
@@ -0,0 +1,130 @@
1
+ import type { Context } from '@midwayjs/koa';
2
+ export declare const LOGGING_KEY = "decorator:logging_key";
3
+ /**
4
+ * 收集好的标准日志数据(用户在 writeLog 方法的参数中拿到)
5
+ */
6
+ export interface CollectedLogData {
7
+ /** 日志标题,取自装饰器配置(如:新增物料) */
8
+ title: string;
9
+ /** 业务类型编码,取自装饰器配置 */
10
+ businessType: number;
11
+ /** 执行的方法名,如 'MaterialController.createMaterial' */
12
+ methodName?: string;
13
+ /** HTTP 请求方法,如 'POST', 'GET' */
14
+ requestMethod: string;
15
+ /** 完整的请求 URL 地址 */
16
+ url: string;
17
+ /** 客户端 IP 地址 */
18
+ ip: string;
19
+ /**
20
+ * 请求参数(JSON 字符串格式)。
21
+ * 注意:内部已经自动处理了 Map、BigInt 等复杂类型,并自动脱敏了 password、token 等敏感字段。
22
+ */
23
+ operParam: string | null;
24
+ /**
25
+ * 响应结果(JSON 字符串格式)。
26
+ * 注意:根据 maxRawLength 自动截断防止撑爆数据库;根据 logMode 自动摘要。
27
+ */
28
+ jsonResult: string | null;
29
+ /** 操作状态:0 表示成功,1 表示发生异常失败 */
30
+ operStatus: number;
31
+ /** 失败时的错误信息,成功时为 null */
32
+ errorMsg: string | null;
33
+ /** 请求开始时间 */
34
+ startTime: Date;
35
+ /** 请求结束时间 */
36
+ endTime: Date;
37
+ /** 接口总耗时(毫秒) */
38
+ costTime: number;
39
+ }
40
+ /**
41
+ * 装饰器入参配置(用户在使用 @Log() 时看到的提示)
42
+ */
43
+ export interface LogOptions {
44
+ /**
45
+ * 日志标题(将写入数据库的 title 字段)。
46
+ * @example '新增物料'
47
+ */
48
+ title?: string;
49
+ /**
50
+ * 业务类型编码(可选),用于区分不同类型的操作。
51
+ * @example 1
52
+ */
53
+ businessType?: number;
54
+ /**
55
+ * 是否记录本次请求日志。
56
+ * - 设置为 `false` 时,请求成功不记日志,但**发生报错时依然会记录**(保证审计底线)。
57
+ * @default true
58
+ */
59
+ needLog?: boolean;
60
+ /**
61
+ * 是否记录接口的返回结果(jsonResult 字段)。
62
+ * - 设置为 `false` 时,成功时记录 `"[已按配置省略]"`,失败时依然记录错误响应。
63
+ * @default true
64
+ */
65
+ logResult?: boolean;
66
+ /**
67
+ * 日志记录模式:
68
+ * - `'full'`:原样记录完整返回结果(可能很大)。
69
+ * - `'summary'`:智能摘要模式,如果返回的是数组,只记录前 N 条(由 maxSampleCount 决定)。
70
+ * @default 'summary'
71
+ */
72
+ logMode?: 'full' | 'summary';
73
+ /**
74
+ * 当 `logMode: 'summary'` 时生效。数组超过此条数时进行截断摘要。
75
+ * @default 3
76
+ */
77
+ maxSampleCount?: number;
78
+ /**
79
+ * 结果序列化后,超过此字符数时进行截断保护,防止数据库字段超长。
80
+ * @default 8000
81
+ */
82
+ maxRawLength?: number;
83
+ /**
84
+ * 需要采集哪些参数源(body、query、params)。
85
+ * @example ['body', 'query']
86
+ * @default ['body', 'query', 'params']
87
+ */
88
+ collectSource?: Array<'body' | 'query' | 'params'>;
89
+ }
90
+ /**
91
+ * 业务方全局配置(在 config.default.ts 中配置)
92
+ */
93
+ export interface OperationLogConfig {
94
+ /**
95
+ * 是否启用操作日志全局开关。
96
+ * @default true
97
+ */
98
+ enable?: boolean;
99
+ /**
100
+ * 是否使用 Redis (BullMQ) 队列。
101
+ * - `false`:使用内置内存队列(速度快,重启可能丢失少量日志)。
102
+ * - `true`:使用 Redis 持久化队列(高可靠,需额外安装 `@midwayjs/bullmq`)。
103
+ * @default false
104
+ */
105
+ useRedis?: boolean;
106
+ /**
107
+ * Redis 队列的名称。
108
+ * @default 'operation-log'
109
+ */
110
+ redisQueueName?: string;
111
+ /**
112
+ * ⭐️ 核心:业务方必须在此实现自己的写库逻辑。
113
+ * @param ctx 当前请求的 Koa Context
114
+ * @param logData 组件为你准备好的、脱敏且安全的日志数据
115
+ * @example
116
+ * ```typescript
117
+ * writeLog: async (ctx, logData) => {
118
+ * await prisma.materialcode_oper_log.create({
119
+ * data: {
120
+ * title: logData.title,
121
+ * method: logData.methodName,
122
+ * params: logData.operParam,
123
+ * // ... 其他字段映射
124
+ * }
125
+ * });
126
+ * }
127
+ * ```
128
+ */
129
+ writeLog: (ctx: Context, logData: CollectedLogData) => Promise<void> | void;
130
+ }
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LOGGING_KEY = void 0;
4
+ exports.LOGGING_KEY = 'decorator:logging_key';
5
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW50ZXJmYWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2ludGVyZmFjZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFFYSxRQUFBLFdBQVcsR0FBRyx1QkFBdUIsQ0FBQyJ9
@@ -0,0 +1,10 @@
1
+ import type { IMiddleware } from '@midwayjs/core';
2
+ import type { NextFunction, Context } from '@midwayjs/koa';
3
+ import type { OperationLogConfig } from '../interface';
4
+ import type { LogQueue } from '../queue/queue.interface';
5
+ export declare class ReportMiddleware implements IMiddleware<Context, NextFunction> {
6
+ logConfig: OperationLogConfig;
7
+ logQueue: LogQueue;
8
+ resolve(): (ctx: Context, next: NextFunction) => Promise<any>;
9
+ static getName(): string;
10
+ }
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.ReportMiddleware = void 0;
13
+ const core_1 = require("@midwayjs/core");
14
+ const index_1 = require("../utils/index");
15
+ const queue_interface_1 = require("../queue/queue.interface");
16
+ let ReportMiddleware = class ReportMiddleware {
17
+ resolve() {
18
+ return async (ctx, next) => {
19
+ if (this.logConfig?.enable === false) {
20
+ return next();
21
+ }
22
+ const startTime = new Date();
23
+ const st = Date.now();
24
+ let operStatus = 0;
25
+ let errorMsg = null;
26
+ try {
27
+ await next();
28
+ }
29
+ catch (error) {
30
+ operStatus = 1;
31
+ errorMsg = error?.message || String(error);
32
+ throw error;
33
+ }
34
+ finally {
35
+ const logMeta = ctx.state?.__log_meta__;
36
+ if (logMeta) {
37
+ const logCfg = (logMeta.options?.metadata?.log ?? {});
38
+ const methodName = logMeta.methodName;
39
+ const decoratorOn = logCfg.needLog !== false;
40
+ if ((decoratorOn || operStatus === 1) && this.logQueue) {
41
+ const network = (0, index_1.getNetworkInfo)(ctx);
42
+ let jsonResult = null;
43
+ if (logCfg.logResult !== false || operStatus === 1) {
44
+ if (logCfg.logMode === 'summary') {
45
+ jsonResult = (0, index_1.safeStringify)((0, index_1.summarize)(ctx.body, logCfg.maxSampleCount), logCfg.maxRawLength);
46
+ }
47
+ else {
48
+ jsonResult = (0, index_1.safeStringify)(ctx.body, logCfg.maxRawLength);
49
+ }
50
+ }
51
+ else {
52
+ jsonResult = '[已按配置省略]';
53
+ }
54
+ const logData = {
55
+ title: logCfg.title ?? '未命名操作',
56
+ businessType: logCfg.businessType ?? 0,
57
+ methodName: methodName,
58
+ requestMethod: ctx.method,
59
+ url: network.url,
60
+ ip: network.ip,
61
+ operParam: (0, index_1.sanitizeParams)(ctx, logCfg.collectSource ?? ['body', 'query', 'params']),
62
+ jsonResult: jsonResult,
63
+ operStatus,
64
+ errorMsg,
65
+ startTime,
66
+ endTime: new Date(),
67
+ costTime: Date.now() - st,
68
+ };
69
+ this.logQueue.push(ctx, logData).catch((err) => {
70
+ ctx.logger.error('[OperationLog] 入队失败', err);
71
+ });
72
+ }
73
+ }
74
+ }
75
+ };
76
+ }
77
+ static getName() {
78
+ return 'reportMiddleware';
79
+ }
80
+ };
81
+ exports.ReportMiddleware = ReportMiddleware;
82
+ __decorate([
83
+ (0, core_1.Config)('operationLog'),
84
+ __metadata("design:type", Object)
85
+ ], ReportMiddleware.prototype, "logConfig", void 0);
86
+ __decorate([
87
+ (0, core_1.Inject)(queue_interface_1.LOG_QUEUE_TOKEN),
88
+ __metadata("design:type", Object)
89
+ ], ReportMiddleware.prototype, "logQueue", void 0);
90
+ exports.ReportMiddleware = ReportMiddleware = __decorate([
91
+ (0, core_1.Middleware)()
92
+ ], ReportMiddleware);
93
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVwb3J0Lm1pZGRsZXdhcmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvbWlkZGxld2FyZS9yZXBvcnQubWlkZGxld2FyZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7QUFBQSx5Q0FBNEQ7QUFJNUQsMENBQTBGO0FBQzFGLDhEQUEyRDtBQUlwRCxJQUFNLGdCQUFnQixHQUF0QixNQUFNLGdCQUFnQjtJQU96QixPQUFPO1FBQ0gsT0FBTyxLQUFLLEVBQUUsR0FBWSxFQUFFLElBQWtCLEVBQUUsRUFBRTtZQUM5QyxJQUFJLElBQUksQ0FBQyxTQUFTLEVBQUUsTUFBTSxLQUFLLEtBQUssRUFBRSxDQUFDO2dCQUNuQyxPQUFPLElBQUksRUFBRSxDQUFDO1lBQ2xCLENBQUM7WUFFRCxNQUFNLFNBQVMsR0FBRyxJQUFJLElBQUksRUFBRSxDQUFDO1lBQzdCLE1BQU0sRUFBRSxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztZQUN0QixJQUFJLFVBQVUsR0FBRyxDQUFDLENBQUM7WUFDbkIsSUFBSSxRQUFRLEdBQWtCLElBQUksQ0FBQztZQUVuQyxJQUFJLENBQUM7Z0JBQ0QsTUFBTSxJQUFJLEVBQUUsQ0FBQztZQUNqQixDQUFDO1lBQUMsT0FBTyxLQUFVLEVBQUUsQ0FBQztnQkFDbEIsVUFBVSxHQUFHLENBQUMsQ0FBQztnQkFDZixRQUFRLEdBQUcsS0FBSyxFQUFFLE9BQU8sSUFBSSxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7Z0JBQzNDLE1BQU0sS0FBSyxDQUFDO1lBQ2hCLENBQUM7b0JBQVMsQ0FBQztnQkFDUCxNQUFNLE9BQU8sR0FBRyxHQUFHLENBQUMsS0FBSyxFQUFFLFlBQVksQ0FBQztnQkFDeEMsSUFBSSxPQUFPLEVBQUUsQ0FBQztvQkFDVixNQUFNLE1BQU0sR0FBRyxDQUFDLE9BQU8sQ0FBQyxPQUFPLEVBQUUsUUFBUSxFQUFFLEdBQUcsSUFBSSxFQUFFLENBQWUsQ0FBQztvQkFDcEUs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
@@ -0,0 +1,14 @@
1
+ import type { ILogger } from '@midwayjs/core';
2
+ import { type LogQueue } from './queue.interface';
3
+ import type { CollectedLogData, OperationLogConfig } from '../interface';
4
+ export declare class MemoryLogQueue implements LogQueue {
5
+ logConfig: OperationLogConfig;
6
+ logger: ILogger;
7
+ private tasks;
8
+ private isProcessing;
9
+ private timer;
10
+ init(): Promise<void>;
11
+ push(ctx: any, logData: CollectedLogData): Promise<void>;
12
+ private process;
13
+ destroy(): Promise<void>;
14
+ }
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.MemoryLogQueue = void 0;
13
+ const core_1 = require("@midwayjs/core");
14
+ const queue_interface_1 = require("./queue.interface");
15
+ let MemoryLogQueue = class MemoryLogQueue {
16
+ constructor() {
17
+ this.tasks = [];
18
+ this.isProcessing = false;
19
+ }
20
+ async init() {
21
+ this.timer = setInterval(() => this.process(), 1000);
22
+ }
23
+ async push(ctx, logData) {
24
+ this.tasks.push({ ctx, data: logData });
25
+ this.process();
26
+ }
27
+ async process() {
28
+ if (this.isProcessing || this.tasks.length === 0)
29
+ return;
30
+ this.isProcessing = true;
31
+ const batch = this.tasks.splice(0, 50);
32
+ try {
33
+ for (const item of batch) {
34
+ if (typeof this.logConfig.writeLog === 'function') {
35
+ await this.logConfig.writeLog(item.ctx, item.data);
36
+ }
37
+ }
38
+ }
39
+ catch (err) {
40
+ this.logger.error('[OperationLog] 内存队列写入日志失败', err);
41
+ }
42
+ finally {
43
+ this.isProcessing = false;
44
+ if (this.tasks.length > 0)
45
+ setImmediate(() => this.process());
46
+ }
47
+ }
48
+ async destroy() {
49
+ clearInterval(this.timer);
50
+ while (this.tasks.length > 0) {
51
+ await this.process();
52
+ }
53
+ }
54
+ };
55
+ exports.MemoryLogQueue = MemoryLogQueue;
56
+ __decorate([
57
+ (0, core_1.Config)('operationLog'),
58
+ __metadata("design:type", Object)
59
+ ], MemoryLogQueue.prototype, "logConfig", void 0);
60
+ __decorate([
61
+ (0, core_1.Inject)(),
62
+ __metadata("design:type", Object)
63
+ ], MemoryLogQueue.prototype, "logger", void 0);
64
+ __decorate([
65
+ (0, core_1.Init)(),
66
+ __metadata("design:type", Function),
67
+ __metadata("design:paramtypes", []),
68
+ __metadata("design:returntype", Promise)
69
+ ], MemoryLogQueue.prototype, "init", null);
70
+ __decorate([
71
+ (0, core_1.Destroy)(),
72
+ __metadata("design:type", Function),
73
+ __metadata("design:paramtypes", []),
74
+ __metadata("design:returntype", Promise)
75
+ ], MemoryLogQueue.prototype, "destroy", null);
76
+ exports.MemoryLogQueue = MemoryLogQueue = __decorate([
77
+ (0, core_1.Provide)(queue_interface_1.LOG_QUEUE_TOKEN),
78
+ (0, core_1.Scope)(core_1.ScopeEnum.Singleton)
79
+ ], MemoryLogQueue);
80
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVtb3J5LnF1ZXVlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3F1ZXVlL21lbW9yeS5xdWV1ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7QUFBQSx5Q0FBMEY7QUFFMUYsdURBQW1FO0FBSzVELElBQU0sY0FBYyxHQUFwQixNQUFNLGNBQWM7SUFBcEI7UUFPSyxVQUFLLEdBQWdELEVBQUUsQ0FBQztRQUN4RCxpQkFBWSxHQUFHLEtBQUssQ0FBQztJQXNDakMsQ0FBQztJQWxDUyxBQUFOLEtBQUssQ0FBQyxJQUFJO1FBQ04sSUFBSSxDQUFDLEtBQUssR0FBRyxXQUFXLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxFQUFFLElBQUksQ0FBQyxDQUFDO0lBQ3pELENBQUM7SUFFRCxLQUFLLENBQUMsSUFBSSxDQUFDLEdBQVEsRUFBRSxPQUF5QjtRQUMxQyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxFQUFFLEdBQUcsRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQztRQUN4QyxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7SUFDbkIsQ0FBQztJQUVPLEtBQUssQ0FBQyxPQUFPO1FBQ2pCLElBQUksSUFBSSxDQUFDLFlBQVksSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sS0FBSyxDQUFDO1lBQUUsT0FBTztRQUN6RCxJQUFJLENBQUMsWUFBWSxHQUFHLElBQUksQ0FBQztRQUN6QixNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFDdkMsSUFBSSxDQUFDO1lBQ0QsS0FBSyxNQUFNLElBQUksSUFBSSxLQUFLLEVBQUUsQ0FBQztnQkFDdkIsSUFBSSxPQUFPLElBQUksQ0FBQyxTQUFTLENBQUMsUUFBUSxLQUFLLFVBQVUsRUFBRSxDQUFDO29CQUNoRCxNQUFNLElBQUksQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO2dCQUN2RCxDQUFDO1lBQ0wsQ0FBQztRQUNMLENBQUM7UUFBQyxPQUFPLEdBQUcsRUFBRSxDQUFDO1lBQ1gsSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsMkJBQTJCLEVBQUUsR0FBRyxDQUFDLENBQUM7UUFDeEQsQ0FBQztnQkFBUyxDQUFDO1lBQ1AsSUFBSSxDQUFDLFlBQVksR0FBRyxLQUFLLENBQUM7WUFDMUIsSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sR0FBRyxDQUFDO2dCQUFFLFlBQVksQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQztRQUNsRSxDQUFDO0lBQ0wsQ0FBQztJQUdLLEFBQU4sS0FBSyxDQUFDLE9BQU87UUFDVCxhQUFhLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzFCLE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDM0IsTUFBTSxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDekIsQ0FBQztJQUNMLENBQUM7Q0FDSixDQUFBO0FBOUNZLHdDQUFjO0FBRXZCO0lBREMsSUFBQSxhQUFNLEVBQUMsY0FBYyxDQUFDOztpREFDTztBQUc5QjtJQURDLElBQUEsYUFBTSxHQUFFOzs4Q0FDTztBQU9WO0lBREwsSUFBQSxXQUFJLEdBQUU7Ozs7MENBR047QUEwQks7SUFETCxJQUFBLGNBQU8sR0FBRTs7Ozs2Q0FNVDt5QkE3Q1EsY0FBYztJQUYxQixJQUFBLGNBQU8sRUFBQyxpQ0FBZSxDQUFDO0lBQ3hCLElBQUEsWUFBSyxFQUFDLGdCQUFTLENBQUMsU0FBUyxDQUFDO0dBQ2QsY0FBYyxDQThDMUIifQ==
@@ -0,0 +1,5 @@
1
+ import type { CollectedLogData } from '../interface';
2
+ export declare const LOG_QUEUE_TOKEN = "LOG_QUEUE_TOKEN";
3
+ export interface LogQueue {
4
+ push(ctx: any, logData: CollectedLogData): Promise<void>;
5
+ }
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LOG_QUEUE_TOKEN = void 0;
4
+ exports.LOG_QUEUE_TOKEN = 'LOG_QUEUE_TOKEN';
5
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicXVldWUuaW50ZXJmYWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3F1ZXVlL3F1ZXVlLmludGVyZmFjZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFFYSxRQUFBLGVBQWUsR0FBRyxpQkFBaUIsQ0FBQyJ9
@@ -0,0 +1,8 @@
1
+ import type { LogQueue } from './queue.interface';
2
+ import type { CollectedLogData, OperationLogConfig } from '../interface';
3
+ import * as bullmq from '@midwayjs/bullmq';
4
+ export declare class RedisLogQueue implements LogQueue {
5
+ logConfig: OperationLogConfig;
6
+ bullmqFramework: bullmq.Framework;
7
+ push(ctx: any, logData: CollectedLogData): Promise<void>;
8
+ }
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
19
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
20
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
21
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
22
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
23
+ };
24
+ var __importStar = (this && this.__importStar) || (function () {
25
+ var ownKeys = function(o) {
26
+ ownKeys = Object.getOwnPropertyNames || function (o) {
27
+ var ar = [];
28
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
+ return ar;
30
+ };
31
+ return ownKeys(o);
32
+ };
33
+ return function (mod) {
34
+ if (mod && mod.__esModule) return mod;
35
+ var result = {};
36
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
+ __setModuleDefault(result, mod);
38
+ return result;
39
+ };
40
+ })();
41
+ var __metadata = (this && this.__metadata) || function (k, v) {
42
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
43
+ };
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ exports.RedisLogQueue = void 0;
46
+ const core_1 = require("@midwayjs/core");
47
+ const bullmq = __importStar(require("@midwayjs/bullmq"));
48
+ let RedisLogQueue = class RedisLogQueue {
49
+ ;
50
+ async push(ctx, logData) {
51
+ if (!this.bullmqFramework) {
52
+ throw new Error('请安装并配置 @midwayjs/bullmq 以使用 Redis 模式');
53
+ }
54
+ const queueName = this.logConfig.redisQueueName || 'operation-log';
55
+ const queue = this.bullmqFramework.getQueue(queueName);
56
+ await queue.add('write-log', logData, {
57
+ attempts: 3,
58
+ backoff: { type: 'exponential', delay: 1000 },
59
+ });
60
+ }
61
+ };
62
+ exports.RedisLogQueue = RedisLogQueue;
63
+ __decorate([
64
+ (0, core_1.Config)('operationLog'),
65
+ __metadata("design:type", Object)
66
+ ], RedisLogQueue.prototype, "logConfig", void 0);
67
+ __decorate([
68
+ (0, core_1.Inject)('bullmqFramework'),
69
+ __metadata("design:type", bullmq.Framework)
70
+ ], RedisLogQueue.prototype, "bullmqFramework", void 0);
71
+ exports.RedisLogQueue = RedisLogQueue = __decorate([
72
+ (0, core_1.Provide)('RedisLogQueue'),
73
+ (0, core_1.Scope)(core_1.ScopeEnum.Singleton)
74
+ ], RedisLogQueue);
75
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVkaXMucXVldWUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcXVldWUvcmVkaXMucXVldWUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUEseUNBQTJFO0FBRzNFLHlEQUEyQztBQUlwQyxJQUFNLGFBQWEsR0FBbkIsTUFBTSxhQUFhO0lBS1ksQ0FBQztJQUVuQyxLQUFLLENBQUMsSUFBSSxDQUFDLEdBQVEsRUFBRSxPQUF5QjtRQUMxQyxJQUFJLENBQUMsSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFDO1lBQ3hCLE1BQU0sSUFBSSxLQUFLLENBQUMsc0NBQXNDLENBQUMsQ0FBQztRQUM1RCxDQUFDO1FBQ0QsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxjQUFjLElBQUksZUFBZSxDQUFDO1FBQ25FLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxlQUFlLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBRXZELE1BQU0sS0FBSyxDQUFDLEdBQUcsQ0FBQyxXQUFXLEVBQUUsT0FBTyxFQUFFO1lBQ2xDLFFBQVEsRUFBRSxDQUFDO1lBQ1gsT0FBTyxFQUFFLEVBQUUsSUFBSSxFQUFFLGFBQWEsRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFO1NBQ2hELENBQUMsQ0FBQztJQUNQLENBQUM7Q0FDSixDQUFBO0FBbkJZLHNDQUFhO0FBRXRCO0lBREMsSUFBQSxhQUFNLEVBQUMsY0FBYyxDQUFDOztnREFDTztBQUc5QjtJQURDLElBQUEsYUFBTSxFQUFDLGlCQUFpQixDQUFDOzhCQUNULE1BQU0sQ0FBQyxTQUFTO3NEQUFDO3dCQUx6QixhQUFhO0lBRnpCLElBQUEsY0FBTyxFQUFDLGVBQWUsQ0FBQztJQUN4QixJQUFBLFlBQUssRUFBQyxnQkFBUyxDQUFDLFNBQVMsQ0FBQztHQUNkLGFBQWEsQ0FtQnpCIn0=
@@ -0,0 +1,8 @@
1
+ import type { Context } from '@midwayjs/koa';
2
+ export declare function getNetworkInfo(ctx: Context): {
3
+ ip: any;
4
+ url: string;
5
+ };
6
+ export declare function safeStringify(obj: any, maxLen?: number): string | null;
7
+ export declare function sanitizeParams(ctx: Context, sources: string[]): string | null;
8
+ export declare function summarize(data: any, maxSample?: number): any;
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getNetworkInfo = getNetworkInfo;
4
+ exports.safeStringify = safeStringify;
5
+ exports.sanitizeParams = sanitizeParams;
6
+ exports.summarize = summarize;
7
+ function getNetworkInfo(ctx) {
8
+ const protocol = ctx.get('X-Forwarded-Proto') || ctx.protocol;
9
+ const host = ctx.get('X-Forwarded-Host') || ctx.host;
10
+ return {
11
+ ip: ctx.request.ip || ctx.ip || 'unknown',
12
+ url: `${protocol}://${host}${ctx.originalUrl}`,
13
+ };
14
+ }
15
+ function safeStringify(obj, maxLen = 8000) {
16
+ if (obj === undefined || obj === null)
17
+ return null;
18
+ const cache = new Set();
19
+ try {
20
+ const str = JSON.stringify(obj, (key, value) => {
21
+ if (typeof value === 'bigint')
22
+ return value.toString();
23
+ if (value instanceof Map)
24
+ return Object.fromEntries(value);
25
+ if (value instanceof Date)
26
+ return value.toISOString();
27
+ if (typeof value === 'object' && value !== null) {
28
+ if (cache.has(value))
29
+ return '[Circular]';
30
+ cache.add(value);
31
+ }
32
+ return value;
33
+ });
34
+ return str.length > maxLen ? str.slice(0, maxLen) + '...' : str;
35
+ }
36
+ catch (e) {
37
+ return '[序列化失败]';
38
+ }
39
+ }
40
+ function sanitizeParams(ctx, sources) {
41
+ const combined = {};
42
+ if (sources.includes('params'))
43
+ combined.params = { ...ctx.params };
44
+ if (sources.includes('query'))
45
+ combined.query = { ...ctx.query };
46
+ if (sources.includes('body'))
47
+ combined.body = ctx.request.body ?? null;
48
+ const SENSITIVE = ['password', 'token', 'secret', 'authorization', 'cvv'];
49
+ const mask = (obj) => {
50
+ if (!obj || typeof obj !== 'object')
51
+ return;
52
+ for (const key of Object.keys(obj)) {
53
+ if (SENSITIVE.includes(key.toLowerCase()))
54
+ obj[key] = '******';
55
+ else if (typeof obj[key] === 'object')
56
+ mask(obj[key]);
57
+ }
58
+ };
59
+ mask(combined);
60
+ return safeStringify(combined);
61
+ }
62
+ function summarize(data, maxSample = 3) {
63
+ if (Array.isArray(data)) {
64
+ if (data.length <= maxSample)
65
+ return data.map(v => summarize(v, maxSample));
66
+ return {
67
+ __summarized__: true,
68
+ total: data.length,
69
+ sample: data.slice(0, maxSample).map(v => summarize(v, maxSample)),
70
+ };
71
+ }
72
+ if (data && typeof data === 'object') {
73
+ const out = {};
74
+ for (const k of Object.keys(data))
75
+ out[k] = summarize(data[k], maxSample);
76
+ return out;
77
+ }
78
+ return data;
79
+ }
80
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdXRpbHMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFFQSx3Q0FPQztBQUVELHNDQWtCQztBQUVELHdDQWdCQztBQUVELDhCQWVDO0FBOURELFNBQWdCLGNBQWMsQ0FBQyxHQUFZO0lBQ3ZDLE1BQU0sUUFBUSxHQUFHLEdBQUcsQ0FBQyxHQUFHLENBQUMsbUJBQW1CLENBQUMsSUFBSSxHQUFHLENBQUMsUUFBUSxDQUFDO0lBQzlELE1BQU0sSUFBSSxHQUFHLEdBQUcsQ0FBQyxHQUFHLENBQUMsa0JBQWtCLENBQUMsSUFBSSxHQUFHLENBQUMsSUFBSSxDQUFDO0lBQ3JELE9BQU87UUFDSCxFQUFFLEVBQUcsR0FBRyxDQUFDLE9BQWUsQ0FBQyxFQUFFLElBQUksR0FBRyxDQUFDLEVBQUUsSUFBSSxTQUFTO1FBQ2xELEdBQUcsRUFBRSxHQUFHLFFBQVEsTUFBTSxJQUFJLEdBQUcsR0FBRyxDQUFDLFdBQVcsRUFBRTtLQUNqRCxDQUFDO0FBQ04sQ0FBQztBQUVELFNBQWdCLGFBQWEsQ0FBQyxHQUFRLEVBQUUsTUFBTSxHQUFHLElBQUk7SUFDakQsSUFBSSxHQUFHLEtBQUssU0FBUyxJQUFJLEdBQUcsS0FBSyxJQUFJO1FBQUUsT0FBTyxJQUFJLENBQUM7SUFDbkQsTUFBTSxLQUFLLEdBQUcsSUFBSSxHQUFHLEVBQUUsQ0FBQztJQUN4QixJQUFJLENBQUM7UUFDRCxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLEdBQUcsRUFBRSxDQUFDLEdBQUcsRUFBRSxLQUFLLEVBQUUsRUFBRTtZQUMzQyxJQUFJLE9BQU8sS0FBSyxLQUFLLFFBQVE7Z0JBQUUsT0FBTyxLQUFLLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDdkQsSUFBSSxLQUFLLFlBQVksR0FBRztnQkFBRSxPQUFPLE1BQU0sQ0FBQyxXQUFXLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDM0QsSUFB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
package/index.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ export * from './dist/index';
2
+
3
+ declare module '@midwayjs/core/dist/interface' {
4
+ interface MidwayConfig {
5
+ operationLog?: import('./dist/interface').OperationLogConfig;
6
+ }
7
+ }
package/package.json CHANGED
@@ -1,6 +1,33 @@
1
1
  {
2
2
  "name": "@jiangnian520/midway-operation-log",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "1.0.1",
4
+ "main": "dist/index.js",
5
+ "typings": "index.d.ts",
6
+ "files": [
7
+ "dist/**/*.js",
8
+ "dist/**/*.d.ts",
9
+ "index.d.ts"
10
+ ],
11
+ "scripts": {
12
+ "build": "mwtsc --cleanOutDir"
13
+ },
14
+ "dependencies": {},
15
+ "peerDependencies": {
16
+ "@midwayjs/core": ">=4.0.0",
17
+ "@midwayjs/koa": ">=4.0.0",
18
+ "@midwayjs/bullmq": ">=4.0.0"
19
+ },
20
+ "peerDependenciesMeta": {
21
+ "@midwayjs/bullmq": {
22
+ "optional": true
23
+ }
24
+ },
25
+ "devDependencies": {
26
+ "@midwayjs/core": "^4.0.0",
27
+ "@midwayjs/koa": "^4.0.0",
28
+ "@midwayjs/bullmq": "^4.0.0",
29
+ "@types/node": "^20.0.0",
30
+ "mwtsc": "^1.4.0",
31
+ "typescript": "^5.3.0"
32
+ }
6
33
  }
package/README.md DELETED
@@ -1,3 +0,0 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.