@lark-apaas/nestjs-logger 0.1.0-alpha.2 → 0.1.0-alpha.4
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.
- package/README.md +320 -0
- package/dist/index.cjs +161 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.js +161 -18
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -32,6 +32,14 @@ declare abstract class BasePinoLogger implements LoggerService {
|
|
|
32
32
|
debug?(message: unknown, ...optionalParams: unknown[]): void;
|
|
33
33
|
verbose?(message: unknown, ...optionalParams: unknown[]): void;
|
|
34
34
|
fatal?(message: unknown, ...optionalParams: unknown[]): void;
|
|
35
|
+
/**
|
|
36
|
+
* 记录结构化日志,将 meta 对象合并到日志字段中
|
|
37
|
+
* @param level 日志级别
|
|
38
|
+
* @param message 消息文本
|
|
39
|
+
* @param meta 要合并的元数据对象
|
|
40
|
+
* @param context 上下文标识
|
|
41
|
+
*/
|
|
42
|
+
logStructured(level: LogLevel, message: string, meta: Record<string, unknown>, context?: string): void;
|
|
35
43
|
protected write(level: LogLevel, message: unknown, optionalParams: unknown[], treatStack?: boolean): void;
|
|
36
44
|
private extractOptionalParams;
|
|
37
45
|
private buildMessagePayload;
|
|
@@ -40,6 +48,8 @@ declare abstract class BasePinoLogger implements LoggerService {
|
|
|
40
48
|
declare class AppLogger extends BasePinoLogger {
|
|
41
49
|
constructor(logger: Logger, requestContext: RequestContextService);
|
|
42
50
|
}
|
|
51
|
+
declare class PinoLoggerService extends BasePinoLogger {
|
|
52
|
+
}
|
|
43
53
|
|
|
44
54
|
declare class LoggerModule {
|
|
45
55
|
}
|
|
@@ -59,4 +69,4 @@ declare class LoggerContextMiddleware implements NestMiddleware {
|
|
|
59
69
|
|
|
60
70
|
declare const TRACE_LOGGER: unique symbol;
|
|
61
71
|
|
|
62
|
-
export { AppLogger, LoggerContextMiddleware, LoggerModule, TRACE_LOGGER };
|
|
72
|
+
export { AppLogger, LoggerContextMiddleware, LoggerModule, PinoLoggerService, TRACE_LOGGER };
|
package/dist/index.d.ts
CHANGED
|
@@ -32,6 +32,14 @@ declare abstract class BasePinoLogger implements LoggerService {
|
|
|
32
32
|
debug?(message: unknown, ...optionalParams: unknown[]): void;
|
|
33
33
|
verbose?(message: unknown, ...optionalParams: unknown[]): void;
|
|
34
34
|
fatal?(message: unknown, ...optionalParams: unknown[]): void;
|
|
35
|
+
/**
|
|
36
|
+
* 记录结构化日志,将 meta 对象合并到日志字段中
|
|
37
|
+
* @param level 日志级别
|
|
38
|
+
* @param message 消息文本
|
|
39
|
+
* @param meta 要合并的元数据对象
|
|
40
|
+
* @param context 上下文标识
|
|
41
|
+
*/
|
|
42
|
+
logStructured(level: LogLevel, message: string, meta: Record<string, unknown>, context?: string): void;
|
|
35
43
|
protected write(level: LogLevel, message: unknown, optionalParams: unknown[], treatStack?: boolean): void;
|
|
36
44
|
private extractOptionalParams;
|
|
37
45
|
private buildMessagePayload;
|
|
@@ -40,6 +48,8 @@ declare abstract class BasePinoLogger implements LoggerService {
|
|
|
40
48
|
declare class AppLogger extends BasePinoLogger {
|
|
41
49
|
constructor(logger: Logger, requestContext: RequestContextService);
|
|
42
50
|
}
|
|
51
|
+
declare class PinoLoggerService extends BasePinoLogger {
|
|
52
|
+
}
|
|
43
53
|
|
|
44
54
|
declare class LoggerModule {
|
|
45
55
|
}
|
|
@@ -59,4 +69,4 @@ declare class LoggerContextMiddleware implements NestMiddleware {
|
|
|
59
69
|
|
|
60
70
|
declare const TRACE_LOGGER: unique symbol;
|
|
61
71
|
|
|
62
|
-
export { AppLogger, LoggerContextMiddleware, LoggerModule, TRACE_LOGGER };
|
|
72
|
+
export { AppLogger, LoggerContextMiddleware, LoggerModule, PinoLoggerService, TRACE_LOGGER };
|
package/dist/index.js
CHANGED
|
@@ -14511,6 +14511,36 @@ var BasePinoLogger = class _BasePinoLogger {
|
|
|
14511
14511
|
fatal(message, ...optionalParams) {
|
|
14512
14512
|
this.write("fatal", message, optionalParams, true);
|
|
14513
14513
|
}
|
|
14514
|
+
/**
|
|
14515
|
+
* 记录结构化日志,将 meta 对象合并到日志字段中
|
|
14516
|
+
* @param level 日志级别
|
|
14517
|
+
* @param message 消息文本
|
|
14518
|
+
* @param meta 要合并的元数据对象
|
|
14519
|
+
* @param context 上下文标识
|
|
14520
|
+
*/
|
|
14521
|
+
logStructured(level, message, meta, context) {
|
|
14522
|
+
if (!this.levelState.isEnabled(level)) {
|
|
14523
|
+
return;
|
|
14524
|
+
}
|
|
14525
|
+
const requestState = this.contextStore.getContext();
|
|
14526
|
+
const traceId = requestState?.requestId ?? null;
|
|
14527
|
+
const payload = {
|
|
14528
|
+
trace_id: traceId,
|
|
14529
|
+
path: requestState?.path,
|
|
14530
|
+
method: requestState?.method,
|
|
14531
|
+
user_id: requestState?.userId ?? null,
|
|
14532
|
+
app_id: requestState?.appId ?? null,
|
|
14533
|
+
tenant_id: requestState?.tenantId ?? null,
|
|
14534
|
+
pid: process.pid,
|
|
14535
|
+
...sanitizeValue(meta)
|
|
14536
|
+
};
|
|
14537
|
+
if (context) {
|
|
14538
|
+
payload.context = context;
|
|
14539
|
+
}
|
|
14540
|
+
const pinoLevel = mapLogLevelToPino(level);
|
|
14541
|
+
const sanitizedPayload = sanitizeValue(payload);
|
|
14542
|
+
this.logger[pinoLevel](sanitizedPayload, message);
|
|
14543
|
+
}
|
|
14514
14544
|
write(level, message, optionalParams, treatStack = false) {
|
|
14515
14545
|
if (!this.levelState.isEnabled(level)) {
|
|
14516
14546
|
return;
|
|
@@ -14669,7 +14699,7 @@ function sanitizeValue(value) {
|
|
|
14669
14699
|
__name(sanitizeValue, "sanitizeValue");
|
|
14670
14700
|
|
|
14671
14701
|
// src/module.ts
|
|
14672
|
-
var
|
|
14702
|
+
var import_config3 = __toESM(require_config2(), 1);
|
|
14673
14703
|
import { Global, Module } from "@nestjs/common";
|
|
14674
14704
|
import { APP_INTERCEPTOR } from "@nestjs/core";
|
|
14675
14705
|
|
|
@@ -14693,15 +14723,22 @@ function normalizeLevel(level) {
|
|
|
14693
14723
|
__name(normalizeLevel, "normalizeLevel");
|
|
14694
14724
|
var logger_config_default = (0, import_config.registerAs)("logger", () => {
|
|
14695
14725
|
const level = normalizeLevel(process.env.LOGGER_LEVEL || (process.env.NODE_ENV === "production" ? "info" : "debug"));
|
|
14726
|
+
const maxBodyLengthEnv = process.env.LOG_MAX_BODY_LENGTH;
|
|
14727
|
+
const maxBodyLength = maxBodyLengthEnv ? Number(maxBodyLengthEnv) : null;
|
|
14696
14728
|
return {
|
|
14697
14729
|
level,
|
|
14698
|
-
logDir: process.env.LOG_DIR || "logs"
|
|
14730
|
+
logDir: process.env.LOG_DIR || "logs",
|
|
14731
|
+
logRequestBody: process.env.LOG_REQUEST_BODY === "true",
|
|
14732
|
+
logResponseBody: process.env.LOG_RESPONSE_BODY === "true",
|
|
14733
|
+
maxBodyLength,
|
|
14734
|
+
sensitiveFields: (process.env.LOG_SENSITIVE_FIELDS || "password,token,secret,authorization,cookie,apiKey,accessToken,refreshToken").split(",").map((f) => f.trim())
|
|
14699
14735
|
};
|
|
14700
14736
|
});
|
|
14701
14737
|
|
|
14702
14738
|
// src/interceptor/logging.interceptor.ts
|
|
14739
|
+
var import_config2 = __toESM(require_config2(), 1);
|
|
14703
14740
|
var import_operators = __toESM(require_operators(), 1);
|
|
14704
|
-
import { Inject as Inject2, Injectable as Injectable3
|
|
14741
|
+
import { Inject as Inject2, Injectable as Injectable3 } from "@nestjs/common";
|
|
14705
14742
|
function _ts_decorate3(decorators, target, key, desc) {
|
|
14706
14743
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
14707
14744
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -14725,9 +14762,13 @@ var LoggingInterceptor = class {
|
|
|
14725
14762
|
}
|
|
14726
14763
|
traceLogger;
|
|
14727
14764
|
requestContext;
|
|
14728
|
-
|
|
14765
|
+
appLogger;
|
|
14766
|
+
config;
|
|
14767
|
+
constructor(traceLogger, requestContext, appLogger, config) {
|
|
14729
14768
|
this.traceLogger = traceLogger;
|
|
14730
14769
|
this.requestContext = requestContext;
|
|
14770
|
+
this.appLogger = appLogger;
|
|
14771
|
+
this.config = config;
|
|
14731
14772
|
}
|
|
14732
14773
|
intercept(context, next) {
|
|
14733
14774
|
if (context.getType() !== "http") {
|
|
@@ -14746,7 +14787,6 @@ var LoggingInterceptor = class {
|
|
|
14746
14787
|
const baseMeta = {
|
|
14747
14788
|
method,
|
|
14748
14789
|
path: url,
|
|
14749
|
-
requestId: req.requestId ?? req.id,
|
|
14750
14790
|
trace_id: req.requestId ?? req.id,
|
|
14751
14791
|
user_id: req.userContext?.userId ?? null,
|
|
14752
14792
|
tenant_id: req.userContext?.tenantId ?? null,
|
|
@@ -14754,39 +14794,141 @@ var LoggingInterceptor = class {
|
|
|
14754
14794
|
ip: req.ip ?? null,
|
|
14755
14795
|
pid: process.pid
|
|
14756
14796
|
};
|
|
14757
|
-
this.
|
|
14758
|
-
|
|
14797
|
+
this.appLogger.logStructured("log", "HTTP request started", baseMeta, "HTTPTraceInterceptor");
|
|
14798
|
+
const requestMeta = {
|
|
14799
|
+
...baseMeta
|
|
14800
|
+
};
|
|
14801
|
+
if (this.config.logRequestBody && req.body) {
|
|
14802
|
+
requestMeta["request_body"] = this.sanitizeAndTruncate(req.body);
|
|
14803
|
+
}
|
|
14804
|
+
if (this.config.logRequestBody && Object.keys(req.query || {}).length > 0) {
|
|
14805
|
+
requestMeta["query_params"] = this.sanitizeAndTruncate(req.query);
|
|
14806
|
+
}
|
|
14807
|
+
this.traceLogger.logStructured("verbose", "HTTP request started", requestMeta, "HTTPTraceInterceptor");
|
|
14808
|
+
return next.handle().pipe((0, import_operators.tap)((responseData) => {
|
|
14759
14809
|
const durationMs = Date.now() - startedAt;
|
|
14760
14810
|
const statusCode = res.statusCode;
|
|
14761
|
-
this.
|
|
14811
|
+
this.appLogger.logStructured("log", "HTTP request completed", {
|
|
14812
|
+
...baseMeta,
|
|
14813
|
+
status_code: statusCode,
|
|
14814
|
+
duration_ms: durationMs
|
|
14815
|
+
}, "HTTPTraceInterceptor");
|
|
14816
|
+
const responseMeta = {
|
|
14762
14817
|
...baseMeta,
|
|
14763
|
-
statusCode,
|
|
14764
|
-
durationMs
|
|
14765
|
-
}
|
|
14818
|
+
status_code: statusCode,
|
|
14819
|
+
duration_ms: durationMs
|
|
14820
|
+
};
|
|
14821
|
+
if (this.config.logResponseBody && responseData !== void 0) {
|
|
14822
|
+
const contentType = res.getHeader("content-type");
|
|
14823
|
+
const isJsonResponse = this.isJsonContentType(contentType);
|
|
14824
|
+
if (isJsonResponse) {
|
|
14825
|
+
responseMeta["response_body"] = this.sanitizeAndTruncate(responseData);
|
|
14826
|
+
}
|
|
14827
|
+
}
|
|
14828
|
+
this.traceLogger.logStructured("verbose", "HTTP request completed", responseMeta, "HTTPTraceInterceptor");
|
|
14766
14829
|
}), (0, import_operators.catchError)((error) => {
|
|
14767
14830
|
const durationMs = Date.now() - startedAt;
|
|
14768
14831
|
const statusCode = res.statusCode >= 400 ? res.statusCode : 500;
|
|
14832
|
+
const linkMeta = {
|
|
14833
|
+
...baseMeta,
|
|
14834
|
+
status_code: statusCode,
|
|
14835
|
+
duration_ms: durationMs
|
|
14836
|
+
};
|
|
14837
|
+
if (error instanceof Error) {
|
|
14838
|
+
linkMeta["error_message"] = error.message;
|
|
14839
|
+
}
|
|
14840
|
+
this.appLogger.logStructured("log", "HTTP request failed", linkMeta, "HTTPTraceInterceptor");
|
|
14769
14841
|
const meta = {
|
|
14770
14842
|
...baseMeta,
|
|
14771
|
-
statusCode,
|
|
14772
|
-
durationMs
|
|
14843
|
+
status_code: statusCode,
|
|
14844
|
+
duration_ms: durationMs
|
|
14773
14845
|
};
|
|
14774
14846
|
if (error instanceof Error) {
|
|
14775
|
-
|
|
14847
|
+
meta["error"] = {
|
|
14848
|
+
message: error.message,
|
|
14849
|
+
stack: error.stack
|
|
14850
|
+
};
|
|
14776
14851
|
} else {
|
|
14777
|
-
|
|
14852
|
+
meta["error"] = String(error);
|
|
14778
14853
|
}
|
|
14854
|
+
this.traceLogger.logStructured("verbose", "HTTP request failed", meta, "HTTPTraceInterceptor");
|
|
14779
14855
|
throw error;
|
|
14780
14856
|
}));
|
|
14781
14857
|
}
|
|
14858
|
+
/**
|
|
14859
|
+
* 对数据进行脱敏和截断处理
|
|
14860
|
+
*/
|
|
14861
|
+
sanitizeAndTruncate(data) {
|
|
14862
|
+
try {
|
|
14863
|
+
const sanitized = this.maskSensitiveFields(data);
|
|
14864
|
+
if (this.config.maxBodyLength === null) {
|
|
14865
|
+
return sanitized;
|
|
14866
|
+
}
|
|
14867
|
+
const jsonStr = JSON.stringify(sanitized);
|
|
14868
|
+
if (jsonStr.length > this.config.maxBodyLength) {
|
|
14869
|
+
return {
|
|
14870
|
+
_truncated: true,
|
|
14871
|
+
_originalLength: jsonStr.length,
|
|
14872
|
+
_data: jsonStr.substring(0, this.config.maxBodyLength) + "..."
|
|
14873
|
+
};
|
|
14874
|
+
}
|
|
14875
|
+
return sanitized;
|
|
14876
|
+
} catch (error) {
|
|
14877
|
+
return {
|
|
14878
|
+
_error: "Failed to serialize data",
|
|
14879
|
+
_message: error instanceof Error ? error.message : String(error)
|
|
14880
|
+
};
|
|
14881
|
+
}
|
|
14882
|
+
}
|
|
14883
|
+
/**
|
|
14884
|
+
* 判断是否是 JSON 响应类型
|
|
14885
|
+
*/
|
|
14886
|
+
isJsonContentType(contentType) {
|
|
14887
|
+
if (typeof contentType !== "string") {
|
|
14888
|
+
return false;
|
|
14889
|
+
}
|
|
14890
|
+
const contentTypeLower = contentType.toLowerCase();
|
|
14891
|
+
return contentTypeLower.includes("application/json");
|
|
14892
|
+
}
|
|
14893
|
+
/**
|
|
14894
|
+
* 脱敏敏感字段
|
|
14895
|
+
*/
|
|
14896
|
+
maskSensitiveFields(data) {
|
|
14897
|
+
if (data === null || data === void 0) {
|
|
14898
|
+
return data;
|
|
14899
|
+
}
|
|
14900
|
+
if (Array.isArray(data)) {
|
|
14901
|
+
return data.map((item) => this.maskSensitiveFields(item));
|
|
14902
|
+
}
|
|
14903
|
+
if (typeof data === "object") {
|
|
14904
|
+
const result = {};
|
|
14905
|
+
for (const [key, value] of Object.entries(data)) {
|
|
14906
|
+
const lowerKey = key.toLowerCase();
|
|
14907
|
+
const isSensitive = this.config.sensitiveFields.some((field) => lowerKey.includes(field.toLowerCase()));
|
|
14908
|
+
if (isSensitive) {
|
|
14909
|
+
result[key] = "***MASKED***";
|
|
14910
|
+
} else if (typeof value === "object" && value !== null) {
|
|
14911
|
+
result[key] = this.maskSensitiveFields(value);
|
|
14912
|
+
} else {
|
|
14913
|
+
result[key] = value;
|
|
14914
|
+
}
|
|
14915
|
+
}
|
|
14916
|
+
return result;
|
|
14917
|
+
}
|
|
14918
|
+
return data;
|
|
14919
|
+
}
|
|
14782
14920
|
};
|
|
14783
14921
|
LoggingInterceptor = _ts_decorate3([
|
|
14784
14922
|
Injectable3(),
|
|
14785
14923
|
_ts_param2(0, Inject2(TRACE_LOGGER)),
|
|
14924
|
+
_ts_param2(2, Inject2(AppLogger)),
|
|
14925
|
+
_ts_param2(3, Inject2(logger_config_default.KEY)),
|
|
14786
14926
|
_ts_metadata2("design:type", Function),
|
|
14787
14927
|
_ts_metadata2("design:paramtypes", [
|
|
14788
|
-
typeof
|
|
14789
|
-
typeof RequestContextService === "undefined" ? Object : RequestContextService
|
|
14928
|
+
typeof PinoLoggerService === "undefined" ? Object : PinoLoggerService,
|
|
14929
|
+
typeof RequestContextService === "undefined" ? Object : RequestContextService,
|
|
14930
|
+
typeof AppLogger === "undefined" ? Object : AppLogger,
|
|
14931
|
+
typeof import_config2.ConfigType === "undefined" ? Object : import_config2.ConfigType
|
|
14790
14932
|
])
|
|
14791
14933
|
], LoggingInterceptor);
|
|
14792
14934
|
|
|
@@ -14904,7 +15046,7 @@ LoggerModule = _ts_decorate5([
|
|
|
14904
15046
|
Global(),
|
|
14905
15047
|
Module({
|
|
14906
15048
|
imports: [
|
|
14907
|
-
|
|
15049
|
+
import_config3.ConfigModule.forFeature(logger_config_default)
|
|
14908
15050
|
],
|
|
14909
15051
|
providers: [
|
|
14910
15052
|
RequestContextService,
|
|
@@ -14951,6 +15093,7 @@ export {
|
|
|
14951
15093
|
AppLogger,
|
|
14952
15094
|
LoggerContextMiddleware,
|
|
14953
15095
|
LoggerModule,
|
|
15096
|
+
PinoLoggerService,
|
|
14954
15097
|
TRACE_LOGGER
|
|
14955
15098
|
};
|
|
14956
15099
|
//# sourceMappingURL=index.js.map
|