@lark-apaas/observable 1.0.0-alpha.1 → 1.0.0-alpha.2
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/dist/index.cjs +2 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -193,7 +193,8 @@ var AppOTelLoggerSDK = class {
|
|
|
193
193
|
const logExporter = new CustomExporter();
|
|
194
194
|
this.logProcessor = new import_sdk_logs.BatchLogRecordProcessor(logExporter, {
|
|
195
195
|
scheduledDelayMillis: 2e3,
|
|
196
|
-
|
|
196
|
+
// 防止日志聚合过长被截断导致丢失
|
|
197
|
+
maxExportBatchSize: 1
|
|
197
198
|
});
|
|
198
199
|
this.sdk = new import_sdk_node.NodeSDK({
|
|
199
200
|
resource,
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/core/sdk.ts","../src/core/resource-detector.ts","../src/core/exporter.ts","../src/utils/generateUUID.ts","../src/utils/hrTimeToNanoNumber.ts","../src/const.ts","../src/utils/convertAllAttrIntoString.ts"],"sourcesContent":["export { AppOTelLoggerSDK, appSdk } from './core/sdk';\nexport type { ContextProvider } from './type';\n","import { NodeSDK } from '@opentelemetry/sdk-node';\nimport { BatchLogRecordProcessor } from '@opentelemetry/sdk-logs';\nimport { detectResources } from '@opentelemetry/resources';\nimport { logs, SeverityNumber } from '@opentelemetry/api-logs';\nimport { PlatformDetector } from './resource-detector';\nimport type { LogAttributes } from '../type';\nimport { CustomExporter } from './exporter';\n\nexport class AppOTelLoggerSDK {\n private sdk: NodeSDK | null = null;\n private logProcessor: BatchLogRecordProcessor | null = null;\n\n\n start() {\n const resource = detectResources({\n detectors: [new PlatformDetector()],\n });\n\n // 将获取上下文的函数传入 Exporter,保持 SDK 对框架无感\n const logExporter = new CustomExporter();\n \n this.logProcessor = new BatchLogRecordProcessor(logExporter, {\n scheduledDelayMillis: 2000,\n maxExportBatchSize: 10,\n });\n\n this.sdk = new NodeSDK({\n resource,\n logRecordProcessor: this.logProcessor,\n traceExporter: undefined,\n });\n\n this.sdk.start();\n }\n\n /**\n * 用户使用的日志接口\n * 自动合并请求级上下文(由 ContextProvider 提供)\n */\n public log(level: string, message: string, extra: Record<string, unknown> = {}) {\n const logger = logs.getLogger('app-logger');\n const severityNumber = this.mapSeverity(level);\n const severityText = this.mapSeverityText(level);\n\n const mergedAttributes: LogAttributes = {\n ...(extra || {}),\n pid: process.pid,\n };\n\n logger.emit({\n body: message,\n severityNumber,\n severityText,\n attributes: mergedAttributes,\n timestamp: new Date(),\n });\n }\n\n async flush() {\n if (this.logProcessor) {\n await this.logProcessor.forceFlush();\n }\n }\n\n private mapSeverity(level: string): SeverityNumber {\n switch (level.toLowerCase()) {\n case 'trace': return SeverityNumber.TRACE;\n case 'debug': return SeverityNumber.DEBUG;\n case 'info': return SeverityNumber.INFO;\n case 'warn': return SeverityNumber.WARN;\n case 'error': return SeverityNumber.ERROR;\n case 'fatal': return SeverityNumber.FATAL;\n default: return SeverityNumber.INFO;\n }\n }\n\n private mapSeverityText(level: string): string {\n switch (level.toLowerCase()) {\n case 'trace': return 'INFO';\n case 'debug': return 'DEBUG';\n case 'info': return 'INFO';\n case 'warn': return 'WARN';\n case 'error': return 'ERROR';\n case 'fatal': return 'ERROR';\n default: return 'INFO';\n }\n }\n}\n\nexport const appSdk = new AppOTelLoggerSDK();\nexport type { LogAttributes };\n","import { ResourceDetector, ResourceDetectionConfig, DetectedResource } from '@opentelemetry/resources';\n\n/**\n * 业务专属资源探测器\n * 负责从环境变量中提取低代码平台特有的元数据 (Tenant, App, Env)\n */\nexport class PlatformDetector implements ResourceDetector {\n \n /**\n * 实现 detect 接口\n * @param config 探测配置 (可选)\n */\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\n detect(config?: ResourceDetectionConfig): DetectedResource {\n // 1. 从环境变量读取平台级资源字段\n const attributes: Record<string, string | number | boolean> = {};\n\n // 2. 清洗数据:移除 undefined/null/空字符串\n const cleanAttributes = Object.entries(attributes).reduce((acc, [key, value]) => {\n if (value !== undefined && value !== null && value !== '') {\n acc[key] = value;\n }\n return acc;\n }, {} as Record<string, string | number | boolean>);\n\n // 3. 返回 Resource 对象\n return {\n attributes: cleanAttributes,\n }\n }\n}\n\nexport const lowCodeDetector = new PlatformDetector();","import { LogRecordExporter, ReadableLogRecord, } from '@opentelemetry/sdk-logs';\nimport { ExportResult, ExportResultCode } from '@opentelemetry/core';\nimport { Attributes } from '@opentelemetry/api';\nimport { Injectable } from '@nestjs/common';\n\nimport { idGenerator } from '../utils/generateUUID';\nimport { hrTimeToNanosNumber } from '../utils/hrTimeToNanoNumber';\nimport { AppEnv } from '../const';\nimport { convertAttributesToString } from '../utils/convertAllAttrIntoString';\n\n@Injectable()\nexport class CustomExporter implements LogRecordExporter {\n private logPrefix: string = \"force-log-prefix\"\n private logSuffix: string = \"force-log-suffix\"\n constructor() {}\n\n export(logs: ReadableLogRecord[], resultCallback: (result: ExportResult) => void) {\n const isDev = process.env.NODE_ENV === \"development\";\n const defaultAttributes: Attributes = {\n uuid: idGenerator.generateTraceId(),\n app_env: isDev ? AppEnv.Dev : AppEnv.Prod,\n };\n\n // 模拟 OTel 的结构化过程\n const otlpLikeStructure = {\n resource: {\n // 合并 OTel Resource(此处暂留空,真实场景可由 sdk.resource 提供)\n attributes: {}\n },\n logRecords: logs.map(log => {\n const rawAttributes = {\n ...defaultAttributes,\n ...(log.attributes ?? {}),\n }\n\n // 将所有属性转换为字符串\n const attributes = convertAttributesToString(rawAttributes);\n\n return {\n timeUnixNano: hrTimeToNanosNumber(log.hrTime),\n observedTimeUnixNano: hrTimeToNanosNumber(log.hrTimeObserved),\n severityNumber: log.severityNumber,\n severityText: log.severityText,\n body: log.body,\n attributes: attributes,\n traceId: log.spanContext?.traceId,\n spanId: log.spanContext?.spanId\n }\n })\n }\n\n console.log(this.logPrefix + JSON.stringify(otlpLikeStructure) + this.logSuffix);\n resultCallback({ code: ExportResultCode.SUCCESS });\n }\n\n async shutdown() { }\n}","import { randomBytes } from 'crypto';\n\nexport const idGenerator = {\n /**\n * 生成 TraceId (128-bit / 32-char hex)\n * 符合 W3C Trace Context 标准\n * 示例: \"5b8efff798038103d269b633813fc60c\"\n */\n generateTraceId(): string {\n // 16 字节 = 128 位,转为 hex 就是 32 个字符\n return randomBytes(16).toString('hex');\n },\n\n /**\n * 生成 SpanId (64-bit / 16-char hex)\n * 示例: \"eee19b7ec3c1b174\"\n */\n generateSpanId(): string {\n // 8 字节 = 64 位,转为 hex 就是 16 个字符\n return randomBytes(8).toString('hex');\n }\n};","import type { HrTime } from '@opentelemetry/api';\n/**\n * 将 HrTime 转换为纳秒数字\n * 注意:JavaScript Number 类型只能精确表示整数到 2^53,对于超过此范围的纳秒值会丢失精度\n*/\nexport function hrTimeToNanosNumber(hrTime: HrTime): number {\n // 将秒转换为 BigInt\n const seconds = BigInt(hrTime[0]);\n // 将纳秒转换为 BigInt\n const nanos = BigInt(hrTime[1]);\n \n // 计算总纳秒数: seconds * 10^9 + nanos\n // 注意:数字后面加 'n' 表示 BigInt 字面量,或者使用 BigInt() 构造函数\n const totalNanos = (seconds * 1_000_000_000n) + nanos;\n \n // 将 BigInt 转换为 Number\n return Number(totalNanos);\n}","export enum AppEnv {\n Dev = \"preview\",\n Prod = \"runtime\",\n}\n","\nconst safeStringify = (obj: unknown) => {\n try {\n return JSON.stringify(obj);\n } catch (error) {\n return '';\n }\n};\n// 将对象的所有属性值转换为字符串\nexport function convertAttributesToString(attributes: Record<string, unknown>): Record<string, string> {\n const result: Record<string, string> = {};\n for (const [key, value] of Object.entries(attributes)) {\n result[key] = value !== undefined && value !== null ? typeof value === 'object' ? safeStringify(value) : String(value) : '';\n }\n return result;\n}"],"mappings":"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","names":["PlatformDetector","detect","config","attributes","cleanAttributes","Object","entries","reduce","acc","key","value","undefined","lowCodeDetector","idGenerator","generateTraceId","randomBytes","toString","generateSpanId","hrTimeToNanosNumber","hrTime","seconds","BigInt","nanos","totalNanos","Number","AppEnv","safeStringify","obj","JSON","stringify","error","convertAttributesToString","attributes","result","key","value","Object","entries","undefined","String","CustomExporter","logPrefix","logSuffix","export","logs","resultCallback","isDev","process","env","NODE_ENV","defaultAttributes","uuid","idGenerator","generateTraceId","app_env","AppEnv","Dev","Prod","otlpLikeStructure","resource","attributes","logRecords","map","log","rawAttributes","convertAttributesToString","timeUnixNano","hrTimeToNanosNumber","hrTime","observedTimeUnixNano","hrTimeObserved","severityNumber","severityText","body","traceId","spanContext","spanId","console","JSON","stringify","code","ExportResultCode","SUCCESS","shutdown","AppOTelLoggerSDK","sdk","logProcessor","start","resource","detectResources","detectors","PlatformDetector","logExporter","CustomExporter","BatchLogRecordProcessor","scheduledDelayMillis","maxExportBatchSize","NodeSDK","logRecordProcessor","traceExporter","undefined","log","level","message","extra","logger","logs","getLogger","severityNumber","mapSeverity","severityText","mapSeverityText","mergedAttributes","pid","process","emit","body","attributes","timestamp","Date","flush","forceFlush","toLowerCase","SeverityNumber","TRACE","DEBUG","INFO","WARN","ERROR","FATAL","appSdk"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/core/sdk.ts","../src/core/resource-detector.ts","../src/core/exporter.ts","../src/utils/generateUUID.ts","../src/utils/hrTimeToNanoNumber.ts","../src/const.ts","../src/utils/convertAllAttrIntoString.ts"],"sourcesContent":["export { AppOTelLoggerSDK, appSdk } from './core/sdk';\nexport type { ContextProvider } from './type';\n","import { NodeSDK } from '@opentelemetry/sdk-node';\nimport { BatchLogRecordProcessor } from '@opentelemetry/sdk-logs';\nimport { detectResources } from '@opentelemetry/resources';\nimport { logs, SeverityNumber } from '@opentelemetry/api-logs';\nimport { PlatformDetector } from './resource-detector';\nimport type { LogAttributes } from '../type';\nimport { CustomExporter } from './exporter';\n\nexport class AppOTelLoggerSDK {\n private sdk: NodeSDK | null = null;\n private logProcessor: BatchLogRecordProcessor | null = null;\n\n\n start() {\n const resource = detectResources({\n detectors: [new PlatformDetector()],\n });\n\n // 将获取上下文的函数传入 Exporter,保持 SDK 对框架无感\n const logExporter = new CustomExporter();\n \n this.logProcessor = new BatchLogRecordProcessor(logExporter, {\n scheduledDelayMillis: 2000,\n // 防止日志聚合过长被截断导致丢失\n maxExportBatchSize: 1,\n });\n\n this.sdk = new NodeSDK({\n resource,\n logRecordProcessor: this.logProcessor,\n traceExporter: undefined,\n });\n\n this.sdk.start();\n }\n\n /**\n * 用户使用的日志接口\n * 自动合并请求级上下文(由 ContextProvider 提供)\n */\n public log(level: string, message: string, extra: Record<string, unknown> = {}) {\n const logger = logs.getLogger('app-logger');\n const severityNumber = this.mapSeverity(level);\n const severityText = this.mapSeverityText(level);\n\n const mergedAttributes: LogAttributes = {\n ...(extra || {}),\n pid: process.pid,\n };\n\n logger.emit({\n body: message,\n severityNumber,\n severityText,\n attributes: mergedAttributes,\n timestamp: new Date(),\n });\n }\n\n async flush() {\n if (this.logProcessor) {\n await this.logProcessor.forceFlush();\n }\n }\n\n private mapSeverity(level: string): SeverityNumber {\n switch (level.toLowerCase()) {\n case 'trace': return SeverityNumber.TRACE;\n case 'debug': return SeverityNumber.DEBUG;\n case 'info': return SeverityNumber.INFO;\n case 'warn': return SeverityNumber.WARN;\n case 'error': return SeverityNumber.ERROR;\n case 'fatal': return SeverityNumber.FATAL;\n default: return SeverityNumber.INFO;\n }\n }\n\n private mapSeverityText(level: string): string {\n switch (level.toLowerCase()) {\n case 'trace': return 'INFO';\n case 'debug': return 'DEBUG';\n case 'info': return 'INFO';\n case 'warn': return 'WARN';\n case 'error': return 'ERROR';\n case 'fatal': return 'ERROR';\n default: return 'INFO';\n }\n }\n}\n\nexport const appSdk = new AppOTelLoggerSDK();\nexport type { LogAttributes };\n","import { ResourceDetector, ResourceDetectionConfig, DetectedResource } from '@opentelemetry/resources';\n\n/**\n * 业务专属资源探测器\n * 负责从环境变量中提取低代码平台特有的元数据 (Tenant, App, Env)\n */\nexport class PlatformDetector implements ResourceDetector {\n \n /**\n * 实现 detect 接口\n * @param config 探测配置 (可选)\n */\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\n detect(config?: ResourceDetectionConfig): DetectedResource {\n // 1. 从环境变量读取平台级资源字段\n const attributes: Record<string, string | number | boolean> = {};\n\n // 2. 清洗数据:移除 undefined/null/空字符串\n const cleanAttributes = Object.entries(attributes).reduce((acc, [key, value]) => {\n if (value !== undefined && value !== null && value !== '') {\n acc[key] = value;\n }\n return acc;\n }, {} as Record<string, string | number | boolean>);\n\n // 3. 返回 Resource 对象\n return {\n attributes: cleanAttributes,\n }\n }\n}\n\nexport const lowCodeDetector = new PlatformDetector();","import { LogRecordExporter, ReadableLogRecord, } from '@opentelemetry/sdk-logs';\nimport { ExportResult, ExportResultCode } from '@opentelemetry/core';\nimport { Attributes } from '@opentelemetry/api';\nimport { Injectable } from '@nestjs/common';\n\nimport { idGenerator } from '../utils/generateUUID';\nimport { hrTimeToNanosNumber } from '../utils/hrTimeToNanoNumber';\nimport { AppEnv } from '../const';\nimport { convertAttributesToString } from '../utils/convertAllAttrIntoString';\n\n@Injectable()\nexport class CustomExporter implements LogRecordExporter {\n private logPrefix: string = \"force-log-prefix\"\n private logSuffix: string = \"force-log-suffix\"\n constructor() {}\n\n export(logs: ReadableLogRecord[], resultCallback: (result: ExportResult) => void) {\n const isDev = process.env.NODE_ENV === \"development\";\n const defaultAttributes: Attributes = {\n uuid: idGenerator.generateTraceId(),\n app_env: isDev ? AppEnv.Dev : AppEnv.Prod,\n };\n\n // 模拟 OTel 的结构化过程\n const otlpLikeStructure = {\n resource: {\n // 合并 OTel Resource(此处暂留空,真实场景可由 sdk.resource 提供)\n attributes: {}\n },\n logRecords: logs.map(log => {\n const rawAttributes = {\n ...defaultAttributes,\n ...(log.attributes ?? {}),\n }\n\n // 将所有属性转换为字符串\n const attributes = convertAttributesToString(rawAttributes);\n\n return {\n timeUnixNano: hrTimeToNanosNumber(log.hrTime),\n observedTimeUnixNano: hrTimeToNanosNumber(log.hrTimeObserved),\n severityNumber: log.severityNumber,\n severityText: log.severityText,\n body: log.body,\n attributes: attributes,\n traceId: log.spanContext?.traceId,\n spanId: log.spanContext?.spanId\n }\n })\n }\n\n console.log(this.logPrefix + JSON.stringify(otlpLikeStructure) + this.logSuffix);\n resultCallback({ code: ExportResultCode.SUCCESS });\n }\n\n async shutdown() { }\n}","import { randomBytes } from 'crypto';\n\nexport const idGenerator = {\n /**\n * 生成 TraceId (128-bit / 32-char hex)\n * 符合 W3C Trace Context 标准\n * 示例: \"5b8efff798038103d269b633813fc60c\"\n */\n generateTraceId(): string {\n // 16 字节 = 128 位,转为 hex 就是 32 个字符\n return randomBytes(16).toString('hex');\n },\n\n /**\n * 生成 SpanId (64-bit / 16-char hex)\n * 示例: \"eee19b7ec3c1b174\"\n */\n generateSpanId(): string {\n // 8 字节 = 64 位,转为 hex 就是 16 个字符\n return randomBytes(8).toString('hex');\n }\n};","import type { HrTime } from '@opentelemetry/api';\n/**\n * 将 HrTime 转换为纳秒数字\n * 注意:JavaScript Number 类型只能精确表示整数到 2^53,对于超过此范围的纳秒值会丢失精度\n*/\nexport function hrTimeToNanosNumber(hrTime: HrTime): number {\n // 将秒转换为 BigInt\n const seconds = BigInt(hrTime[0]);\n // 将纳秒转换为 BigInt\n const nanos = BigInt(hrTime[1]);\n \n // 计算总纳秒数: seconds * 10^9 + nanos\n // 注意:数字后面加 'n' 表示 BigInt 字面量,或者使用 BigInt() 构造函数\n const totalNanos = (seconds * 1_000_000_000n) + nanos;\n \n // 将 BigInt 转换为 Number\n return Number(totalNanos);\n}","export enum AppEnv {\n Dev = \"preview\",\n Prod = \"runtime\",\n}\n","\nconst safeStringify = (obj: unknown) => {\n try {\n return JSON.stringify(obj);\n } catch (error) {\n return '';\n }\n};\n// 将对象的所有属性值转换为字符串\nexport function convertAttributesToString(attributes: Record<string, unknown>): Record<string, string> {\n const result: Record<string, string> = {};\n for (const [key, value] of Object.entries(attributes)) {\n result[key] = value !== undefined && value !== null ? typeof value === 'object' ? safeStringify(value) : String(value) : '';\n }\n return result;\n}"],"mappings":"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","names":["PlatformDetector","detect","config","attributes","cleanAttributes","Object","entries","reduce","acc","key","value","undefined","lowCodeDetector","idGenerator","generateTraceId","randomBytes","toString","generateSpanId","hrTimeToNanosNumber","hrTime","seconds","BigInt","nanos","totalNanos","Number","AppEnv","safeStringify","obj","JSON","stringify","error","convertAttributesToString","attributes","result","key","value","Object","entries","undefined","String","CustomExporter","logPrefix","logSuffix","export","logs","resultCallback","isDev","process","env","NODE_ENV","defaultAttributes","uuid","idGenerator","generateTraceId","app_env","AppEnv","Dev","Prod","otlpLikeStructure","resource","attributes","logRecords","map","log","rawAttributes","convertAttributesToString","timeUnixNano","hrTimeToNanosNumber","hrTime","observedTimeUnixNano","hrTimeObserved","severityNumber","severityText","body","traceId","spanContext","spanId","console","JSON","stringify","code","ExportResultCode","SUCCESS","shutdown","AppOTelLoggerSDK","sdk","logProcessor","start","resource","detectResources","detectors","PlatformDetector","logExporter","CustomExporter","BatchLogRecordProcessor","scheduledDelayMillis","maxExportBatchSize","NodeSDK","logRecordProcessor","traceExporter","undefined","log","level","message","extra","logger","logs","getLogger","severityNumber","mapSeverity","severityText","mapSeverityText","mergedAttributes","pid","process","emit","body","attributes","timestamp","Date","flush","forceFlush","toLowerCase","SeverityNumber","TRACE","DEBUG","INFO","WARN","ERROR","FATAL","appSdk"]}
|
package/dist/index.js
CHANGED
|
@@ -168,7 +168,8 @@ var AppOTelLoggerSDK = class {
|
|
|
168
168
|
const logExporter = new CustomExporter();
|
|
169
169
|
this.logProcessor = new BatchLogRecordProcessor(logExporter, {
|
|
170
170
|
scheduledDelayMillis: 2e3,
|
|
171
|
-
|
|
171
|
+
// 防止日志聚合过长被截断导致丢失
|
|
172
|
+
maxExportBatchSize: 1
|
|
172
173
|
});
|
|
173
174
|
this.sdk = new NodeSDK({
|
|
174
175
|
resource,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/sdk.ts","../src/core/resource-detector.ts","../src/core/exporter.ts","../src/utils/generateUUID.ts","../src/utils/hrTimeToNanoNumber.ts","../src/const.ts","../src/utils/convertAllAttrIntoString.ts"],"sourcesContent":["import { NodeSDK } from '@opentelemetry/sdk-node';\nimport { BatchLogRecordProcessor } from '@opentelemetry/sdk-logs';\nimport { detectResources } from '@opentelemetry/resources';\nimport { logs, SeverityNumber } from '@opentelemetry/api-logs';\nimport { PlatformDetector } from './resource-detector';\nimport type { LogAttributes } from '../type';\nimport { CustomExporter } from './exporter';\n\nexport class AppOTelLoggerSDK {\n private sdk: NodeSDK | null = null;\n private logProcessor: BatchLogRecordProcessor | null = null;\n\n\n start() {\n const resource = detectResources({\n detectors: [new PlatformDetector()],\n });\n\n // 将获取上下文的函数传入 Exporter,保持 SDK 对框架无感\n const logExporter = new CustomExporter();\n \n this.logProcessor = new BatchLogRecordProcessor(logExporter, {\n scheduledDelayMillis: 2000,\n maxExportBatchSize: 10,\n });\n\n this.sdk = new NodeSDK({\n resource,\n logRecordProcessor: this.logProcessor,\n traceExporter: undefined,\n });\n\n this.sdk.start();\n }\n\n /**\n * 用户使用的日志接口\n * 自动合并请求级上下文(由 ContextProvider 提供)\n */\n public log(level: string, message: string, extra: Record<string, unknown> = {}) {\n const logger = logs.getLogger('app-logger');\n const severityNumber = this.mapSeverity(level);\n const severityText = this.mapSeverityText(level);\n\n const mergedAttributes: LogAttributes = {\n ...(extra || {}),\n pid: process.pid,\n };\n\n logger.emit({\n body: message,\n severityNumber,\n severityText,\n attributes: mergedAttributes,\n timestamp: new Date(),\n });\n }\n\n async flush() {\n if (this.logProcessor) {\n await this.logProcessor.forceFlush();\n }\n }\n\n private mapSeverity(level: string): SeverityNumber {\n switch (level.toLowerCase()) {\n case 'trace': return SeverityNumber.TRACE;\n case 'debug': return SeverityNumber.DEBUG;\n case 'info': return SeverityNumber.INFO;\n case 'warn': return SeverityNumber.WARN;\n case 'error': return SeverityNumber.ERROR;\n case 'fatal': return SeverityNumber.FATAL;\n default: return SeverityNumber.INFO;\n }\n }\n\n private mapSeverityText(level: string): string {\n switch (level.toLowerCase()) {\n case 'trace': return 'INFO';\n case 'debug': return 'DEBUG';\n case 'info': return 'INFO';\n case 'warn': return 'WARN';\n case 'error': return 'ERROR';\n case 'fatal': return 'ERROR';\n default: return 'INFO';\n }\n }\n}\n\nexport const appSdk = new AppOTelLoggerSDK();\nexport type { LogAttributes };\n","import { ResourceDetector, ResourceDetectionConfig, DetectedResource } from '@opentelemetry/resources';\n\n/**\n * 业务专属资源探测器\n * 负责从环境变量中提取低代码平台特有的元数据 (Tenant, App, Env)\n */\nexport class PlatformDetector implements ResourceDetector {\n \n /**\n * 实现 detect 接口\n * @param config 探测配置 (可选)\n */\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\n detect(config?: ResourceDetectionConfig): DetectedResource {\n // 1. 从环境变量读取平台级资源字段\n const attributes: Record<string, string | number | boolean> = {};\n\n // 2. 清洗数据:移除 undefined/null/空字符串\n const cleanAttributes = Object.entries(attributes).reduce((acc, [key, value]) => {\n if (value !== undefined && value !== null && value !== '') {\n acc[key] = value;\n }\n return acc;\n }, {} as Record<string, string | number | boolean>);\n\n // 3. 返回 Resource 对象\n return {\n attributes: cleanAttributes,\n }\n }\n}\n\nexport const lowCodeDetector = new PlatformDetector();","import { LogRecordExporter, ReadableLogRecord, } from '@opentelemetry/sdk-logs';\nimport { ExportResult, ExportResultCode } from '@opentelemetry/core';\nimport { Attributes } from '@opentelemetry/api';\nimport { Injectable } from '@nestjs/common';\n\nimport { idGenerator } from '../utils/generateUUID';\nimport { hrTimeToNanosNumber } from '../utils/hrTimeToNanoNumber';\nimport { AppEnv } from '../const';\nimport { convertAttributesToString } from '../utils/convertAllAttrIntoString';\n\n@Injectable()\nexport class CustomExporter implements LogRecordExporter {\n private logPrefix: string = \"force-log-prefix\"\n private logSuffix: string = \"force-log-suffix\"\n constructor() {}\n\n export(logs: ReadableLogRecord[], resultCallback: (result: ExportResult) => void) {\n const isDev = process.env.NODE_ENV === \"development\";\n const defaultAttributes: Attributes = {\n uuid: idGenerator.generateTraceId(),\n app_env: isDev ? AppEnv.Dev : AppEnv.Prod,\n };\n\n // 模拟 OTel 的结构化过程\n const otlpLikeStructure = {\n resource: {\n // 合并 OTel Resource(此处暂留空,真实场景可由 sdk.resource 提供)\n attributes: {}\n },\n logRecords: logs.map(log => {\n const rawAttributes = {\n ...defaultAttributes,\n ...(log.attributes ?? {}),\n }\n\n // 将所有属性转换为字符串\n const attributes = convertAttributesToString(rawAttributes);\n\n return {\n timeUnixNano: hrTimeToNanosNumber(log.hrTime),\n observedTimeUnixNano: hrTimeToNanosNumber(log.hrTimeObserved),\n severityNumber: log.severityNumber,\n severityText: log.severityText,\n body: log.body,\n attributes: attributes,\n traceId: log.spanContext?.traceId,\n spanId: log.spanContext?.spanId\n }\n })\n }\n\n console.log(this.logPrefix + JSON.stringify(otlpLikeStructure) + this.logSuffix);\n resultCallback({ code: ExportResultCode.SUCCESS });\n }\n\n async shutdown() { }\n}","import { randomBytes } from 'crypto';\n\nexport const idGenerator = {\n /**\n * 生成 TraceId (128-bit / 32-char hex)\n * 符合 W3C Trace Context 标准\n * 示例: \"5b8efff798038103d269b633813fc60c\"\n */\n generateTraceId(): string {\n // 16 字节 = 128 位,转为 hex 就是 32 个字符\n return randomBytes(16).toString('hex');\n },\n\n /**\n * 生成 SpanId (64-bit / 16-char hex)\n * 示例: \"eee19b7ec3c1b174\"\n */\n generateSpanId(): string {\n // 8 字节 = 64 位,转为 hex 就是 16 个字符\n return randomBytes(8).toString('hex');\n }\n};","import type { HrTime } from '@opentelemetry/api';\n/**\n * 将 HrTime 转换为纳秒数字\n * 注意:JavaScript Number 类型只能精确表示整数到 2^53,对于超过此范围的纳秒值会丢失精度\n*/\nexport function hrTimeToNanosNumber(hrTime: HrTime): number {\n // 将秒转换为 BigInt\n const seconds = BigInt(hrTime[0]);\n // 将纳秒转换为 BigInt\n const nanos = BigInt(hrTime[1]);\n \n // 计算总纳秒数: seconds * 10^9 + nanos\n // 注意:数字后面加 'n' 表示 BigInt 字面量,或者使用 BigInt() 构造函数\n const totalNanos = (seconds * 1_000_000_000n) + nanos;\n \n // 将 BigInt 转换为 Number\n return Number(totalNanos);\n}","export enum AppEnv {\n Dev = \"preview\",\n Prod = \"runtime\",\n}\n","\nconst safeStringify = (obj: unknown) => {\n try {\n return JSON.stringify(obj);\n } catch (error) {\n return '';\n }\n};\n// 将对象的所有属性值转换为字符串\nexport function convertAttributesToString(attributes: Record<string, unknown>): Record<string, string> {\n const result: Record<string, string> = {};\n for (const [key, value] of Object.entries(attributes)) {\n result[key] = value !== undefined && value !== null ? typeof value === 'object' ? safeStringify(value) : String(value) : '';\n }\n return result;\n}"],"mappings":"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","names":["NodeSDK","BatchLogRecordProcessor","detectResources","logs","SeverityNumber","PlatformDetector","detect","config","attributes","cleanAttributes","Object","entries","reduce","acc","key","value","undefined","lowCodeDetector","ExportResultCode","Injectable","randomBytes","idGenerator","generateTraceId","toString","generateSpanId","hrTimeToNanosNumber","hrTime","seconds","BigInt","nanos","totalNanos","Number","AppEnv","safeStringify","obj","JSON","stringify","error","convertAttributesToString","attributes","result","key","value","Object","entries","undefined","String","CustomExporter","logPrefix","logSuffix","export","logs","resultCallback","isDev","process","env","NODE_ENV","defaultAttributes","uuid","idGenerator","generateTraceId","app_env","AppEnv","Dev","Prod","otlpLikeStructure","resource","attributes","logRecords","map","log","rawAttributes","convertAttributesToString","timeUnixNano","hrTimeToNanosNumber","hrTime","observedTimeUnixNano","hrTimeObserved","severityNumber","severityText","body","traceId","spanContext","spanId","console","JSON","stringify","code","ExportResultCode","SUCCESS","shutdown","AppOTelLoggerSDK","sdk","logProcessor","start","resource","detectResources","detectors","PlatformDetector","logExporter","CustomExporter","BatchLogRecordProcessor","scheduledDelayMillis","maxExportBatchSize","NodeSDK","logRecordProcessor","traceExporter","undefined","log","level","message","extra","logger","logs","getLogger","severityNumber","mapSeverity","severityText","mapSeverityText","mergedAttributes","pid","process","emit","body","attributes","timestamp","Date","flush","forceFlush","toLowerCase","SeverityNumber","TRACE","DEBUG","INFO","WARN","ERROR","FATAL","appSdk"]}
|
|
1
|
+
{"version":3,"sources":["../src/core/sdk.ts","../src/core/resource-detector.ts","../src/core/exporter.ts","../src/utils/generateUUID.ts","../src/utils/hrTimeToNanoNumber.ts","../src/const.ts","../src/utils/convertAllAttrIntoString.ts"],"sourcesContent":["import { NodeSDK } from '@opentelemetry/sdk-node';\nimport { BatchLogRecordProcessor } from '@opentelemetry/sdk-logs';\nimport { detectResources } from '@opentelemetry/resources';\nimport { logs, SeverityNumber } from '@opentelemetry/api-logs';\nimport { PlatformDetector } from './resource-detector';\nimport type { LogAttributes } from '../type';\nimport { CustomExporter } from './exporter';\n\nexport class AppOTelLoggerSDK {\n private sdk: NodeSDK | null = null;\n private logProcessor: BatchLogRecordProcessor | null = null;\n\n\n start() {\n const resource = detectResources({\n detectors: [new PlatformDetector()],\n });\n\n // 将获取上下文的函数传入 Exporter,保持 SDK 对框架无感\n const logExporter = new CustomExporter();\n \n this.logProcessor = new BatchLogRecordProcessor(logExporter, {\n scheduledDelayMillis: 2000,\n // 防止日志聚合过长被截断导致丢失\n maxExportBatchSize: 1,\n });\n\n this.sdk = new NodeSDK({\n resource,\n logRecordProcessor: this.logProcessor,\n traceExporter: undefined,\n });\n\n this.sdk.start();\n }\n\n /**\n * 用户使用的日志接口\n * 自动合并请求级上下文(由 ContextProvider 提供)\n */\n public log(level: string, message: string, extra: Record<string, unknown> = {}) {\n const logger = logs.getLogger('app-logger');\n const severityNumber = this.mapSeverity(level);\n const severityText = this.mapSeverityText(level);\n\n const mergedAttributes: LogAttributes = {\n ...(extra || {}),\n pid: process.pid,\n };\n\n logger.emit({\n body: message,\n severityNumber,\n severityText,\n attributes: mergedAttributes,\n timestamp: new Date(),\n });\n }\n\n async flush() {\n if (this.logProcessor) {\n await this.logProcessor.forceFlush();\n }\n }\n\n private mapSeverity(level: string): SeverityNumber {\n switch (level.toLowerCase()) {\n case 'trace': return SeverityNumber.TRACE;\n case 'debug': return SeverityNumber.DEBUG;\n case 'info': return SeverityNumber.INFO;\n case 'warn': return SeverityNumber.WARN;\n case 'error': return SeverityNumber.ERROR;\n case 'fatal': return SeverityNumber.FATAL;\n default: return SeverityNumber.INFO;\n }\n }\n\n private mapSeverityText(level: string): string {\n switch (level.toLowerCase()) {\n case 'trace': return 'INFO';\n case 'debug': return 'DEBUG';\n case 'info': return 'INFO';\n case 'warn': return 'WARN';\n case 'error': return 'ERROR';\n case 'fatal': return 'ERROR';\n default: return 'INFO';\n }\n }\n}\n\nexport const appSdk = new AppOTelLoggerSDK();\nexport type { LogAttributes };\n","import { ResourceDetector, ResourceDetectionConfig, DetectedResource } from '@opentelemetry/resources';\n\n/**\n * 业务专属资源探测器\n * 负责从环境变量中提取低代码平台特有的元数据 (Tenant, App, Env)\n */\nexport class PlatformDetector implements ResourceDetector {\n \n /**\n * 实现 detect 接口\n * @param config 探测配置 (可选)\n */\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\n detect(config?: ResourceDetectionConfig): DetectedResource {\n // 1. 从环境变量读取平台级资源字段\n const attributes: Record<string, string | number | boolean> = {};\n\n // 2. 清洗数据:移除 undefined/null/空字符串\n const cleanAttributes = Object.entries(attributes).reduce((acc, [key, value]) => {\n if (value !== undefined && value !== null && value !== '') {\n acc[key] = value;\n }\n return acc;\n }, {} as Record<string, string | number | boolean>);\n\n // 3. 返回 Resource 对象\n return {\n attributes: cleanAttributes,\n }\n }\n}\n\nexport const lowCodeDetector = new PlatformDetector();","import { LogRecordExporter, ReadableLogRecord, } from '@opentelemetry/sdk-logs';\nimport { ExportResult, ExportResultCode } from '@opentelemetry/core';\nimport { Attributes } from '@opentelemetry/api';\nimport { Injectable } from '@nestjs/common';\n\nimport { idGenerator } from '../utils/generateUUID';\nimport { hrTimeToNanosNumber } from '../utils/hrTimeToNanoNumber';\nimport { AppEnv } from '../const';\nimport { convertAttributesToString } from '../utils/convertAllAttrIntoString';\n\n@Injectable()\nexport class CustomExporter implements LogRecordExporter {\n private logPrefix: string = \"force-log-prefix\"\n private logSuffix: string = \"force-log-suffix\"\n constructor() {}\n\n export(logs: ReadableLogRecord[], resultCallback: (result: ExportResult) => void) {\n const isDev = process.env.NODE_ENV === \"development\";\n const defaultAttributes: Attributes = {\n uuid: idGenerator.generateTraceId(),\n app_env: isDev ? AppEnv.Dev : AppEnv.Prod,\n };\n\n // 模拟 OTel 的结构化过程\n const otlpLikeStructure = {\n resource: {\n // 合并 OTel Resource(此处暂留空,真实场景可由 sdk.resource 提供)\n attributes: {}\n },\n logRecords: logs.map(log => {\n const rawAttributes = {\n ...defaultAttributes,\n ...(log.attributes ?? {}),\n }\n\n // 将所有属性转换为字符串\n const attributes = convertAttributesToString(rawAttributes);\n\n return {\n timeUnixNano: hrTimeToNanosNumber(log.hrTime),\n observedTimeUnixNano: hrTimeToNanosNumber(log.hrTimeObserved),\n severityNumber: log.severityNumber,\n severityText: log.severityText,\n body: log.body,\n attributes: attributes,\n traceId: log.spanContext?.traceId,\n spanId: log.spanContext?.spanId\n }\n })\n }\n\n console.log(this.logPrefix + JSON.stringify(otlpLikeStructure) + this.logSuffix);\n resultCallback({ code: ExportResultCode.SUCCESS });\n }\n\n async shutdown() { }\n}","import { randomBytes } from 'crypto';\n\nexport const idGenerator = {\n /**\n * 生成 TraceId (128-bit / 32-char hex)\n * 符合 W3C Trace Context 标准\n * 示例: \"5b8efff798038103d269b633813fc60c\"\n */\n generateTraceId(): string {\n // 16 字节 = 128 位,转为 hex 就是 32 个字符\n return randomBytes(16).toString('hex');\n },\n\n /**\n * 生成 SpanId (64-bit / 16-char hex)\n * 示例: \"eee19b7ec3c1b174\"\n */\n generateSpanId(): string {\n // 8 字节 = 64 位,转为 hex 就是 16 个字符\n return randomBytes(8).toString('hex');\n }\n};","import type { HrTime } from '@opentelemetry/api';\n/**\n * 将 HrTime 转换为纳秒数字\n * 注意:JavaScript Number 类型只能精确表示整数到 2^53,对于超过此范围的纳秒值会丢失精度\n*/\nexport function hrTimeToNanosNumber(hrTime: HrTime): number {\n // 将秒转换为 BigInt\n const seconds = BigInt(hrTime[0]);\n // 将纳秒转换为 BigInt\n const nanos = BigInt(hrTime[1]);\n \n // 计算总纳秒数: seconds * 10^9 + nanos\n // 注意:数字后面加 'n' 表示 BigInt 字面量,或者使用 BigInt() 构造函数\n const totalNanos = (seconds * 1_000_000_000n) + nanos;\n \n // 将 BigInt 转换为 Number\n return Number(totalNanos);\n}","export enum AppEnv {\n Dev = \"preview\",\n Prod = \"runtime\",\n}\n","\nconst safeStringify = (obj: unknown) => {\n try {\n return JSON.stringify(obj);\n } catch (error) {\n return '';\n }\n};\n// 将对象的所有属性值转换为字符串\nexport function convertAttributesToString(attributes: Record<string, unknown>): Record<string, string> {\n const result: Record<string, string> = {};\n for (const [key, value] of Object.entries(attributes)) {\n result[key] = value !== undefined && value !== null ? typeof value === 'object' ? safeStringify(value) : String(value) : '';\n }\n return result;\n}"],"mappings":"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","names":["NodeSDK","BatchLogRecordProcessor","detectResources","logs","SeverityNumber","PlatformDetector","detect","config","attributes","cleanAttributes","Object","entries","reduce","acc","key","value","undefined","lowCodeDetector","ExportResultCode","Injectable","randomBytes","idGenerator","generateTraceId","toString","generateSpanId","hrTimeToNanosNumber","hrTime","seconds","BigInt","nanos","totalNanos","Number","AppEnv","safeStringify","obj","JSON","stringify","error","convertAttributesToString","attributes","result","key","value","Object","entries","undefined","String","CustomExporter","logPrefix","logSuffix","export","logs","resultCallback","isDev","process","env","NODE_ENV","defaultAttributes","uuid","idGenerator","generateTraceId","app_env","AppEnv","Dev","Prod","otlpLikeStructure","resource","attributes","logRecords","map","log","rawAttributes","convertAttributesToString","timeUnixNano","hrTimeToNanosNumber","hrTime","observedTimeUnixNano","hrTimeObserved","severityNumber","severityText","body","traceId","spanContext","spanId","console","JSON","stringify","code","ExportResultCode","SUCCESS","shutdown","AppOTelLoggerSDK","sdk","logProcessor","start","resource","detectResources","detectors","PlatformDetector","logExporter","CustomExporter","BatchLogRecordProcessor","scheduledDelayMillis","maxExportBatchSize","NodeSDK","logRecordProcessor","traceExporter","undefined","log","level","message","extra","logger","logs","getLogger","severityNumber","mapSeverity","severityText","mapSeverityText","mergedAttributes","pid","process","emit","body","attributes","timestamp","Date","flush","forceFlush","toLowerCase","SeverityNumber","TRACE","DEBUG","INFO","WARN","ERROR","FATAL","appSdk"]}
|