UNPKG

@mwcp/otel

Version:
212 lines (174 loc) 4.97 kB
import { Inject, Logger, Provide, Singleton, } from '@midwayjs/core' import { ILogger } from '@midwayjs/logger' import { Context } from '@mwcp/share' import type { Attributes, Span } from '@opentelemetry/api' import { OtelComponent } from './component.js' import { TraceService } from './trace.service/index.trace.service.js' import { AttrNames, TraceLogType } from './types.js' /** * 集成链路追踪 AppLogger * - 打印日志同时会在链路上报日志级别和内容 * - 生产环境应设置合理采样率避免过多的日志随链路上报 */ @Singleton() export class TraceAppLogger implements ILogger { @Inject() protected readonly otel: OtelComponent @Logger() protected readonly logger: ILogger debug(msg: unknown, span: Span | undefined | false, ...args: unknown[]): void { this.log({ level: 'debug', msg, args }, span) } info(msg: unknown, span: Span | undefined | false, ...args: unknown[]): void { this.log({ level: 'info', msg, args }, span) } warn(msg: unknown, span: Span | undefined | false, ...args: unknown[]): void { this.log({ level: 'warn', msg, args }, span) } error(msg: unknown, span: Span | undefined | false, ...args: unknown[]): void { this.log({ level: 'error', msg, args }, span) } write(msg: unknown, span: Span | undefined | false, ...args: unknown[]): void { this.log({ level: 'write', msg, args }, span) } verbose(msg: unknown, span: Span | undefined | false, ...args: unknown[]): void { this.log({ level: 'verbose', msg, args }, span) } /** * 打印日志同时会在链路上报日志级别和内容 * @param span * - undefined: 使用请求rootSpan * - false: 仅打印日志,不上报 */ log( input: TraceLogType, span?: Span | false, logger?: ILogger, ): void { if (span !== false) { traceAppLogger(input, this.otel, span) } origLogger(input, logger ?? this.logger) } } /** * 集成链路追踪 Context Logger * - 打印日志同时会在链路上报日志级别和内容 * - 生产环境应设置合理采样率避免过多的日志随链路上报 */ @Provide() export class TraceLogger implements ILogger { @Inject() readonly ctx: Context @Inject() protected readonly logger: ILogger @Inject() protected readonly traceSvc: TraceService @Inject() protected readonly traceAppLogger: TraceAppLogger debug(msg: unknown, ...args: unknown[]): void { this.log({ level: 'debug', msg, args, }) } info(msg: unknown, ...args: unknown[]): void { this.log({ level: 'info', msg, args, }) } warn(msg: unknown, ...args: unknown[]): void { this.log({ level: 'warn', msg, args, }) } error(msg: unknown, ...args: unknown[]): void { this.log({ level: 'error', msg, args, }) } write(msg: unknown, ...args: unknown[]): void { this.log({ level: 'write', msg, args, }) } verbose(msg: unknown, ...args: unknown[]): void { this.log({ level: 'verbose', msg, args, }) } /** * 打印日志同时会在链路上报日志级别和内容 * @param span * - undefined: 使用请求rootSpan * - false: 仅打印日志,不上报 */ log(input: TraceLogType, span?: Span | false): void { const isStarted = this.traceSvc.isStartedMap.get(this.ctx) if (isStarted) { const currSpan = span ?? this.traceSvc.getRootSpan(this.ctx) if (currSpan) { this.traceAppLogger.log(input, currSpan, this.logger) return } } // log w/o trace this.traceAppLogger.log(input, false, this.logger) } } function traceAppLogger( input: TraceLogType, otel: OtelComponent, span: Span | undefined, ): void { const currSpan = span ?? otel.getActiveSpan() if (! currSpan) { return } const { msg, args } = input const level = input.level ?? 'info' const name = input['event'] && typeof input['event'] === 'string' ? input['event'] : 'trace.log' const event: Attributes = { event: name, [AttrNames.LogLevel]: level, } if (typeof msg !== 'undefined') { event[AttrNames.Message] = typeof msg === 'string' ? msg : JSON.stringify(msg) } if (typeof args !== 'undefined') { event['log.detail'] = JSON.stringify(args) } otel.addEvent(currSpan, event) } function origLogger( input: TraceLogType, logger: ILogger, ): void { const { msg, args } = input const level = input.level ?? 'info' if (typeof msg === 'undefined') { logger[level](input) } else if (Array.isArray(args)) { logger[level](msg, ...args) } else { logger[level](msg) } } // interface ILogger extends IMidwayLogger { // info(msg: unknown, ...args: unknown[]): void // debug(msg: unknown, ...args: unknown[]): void // error(msg: unknown, ...args: unknown[]): void // warn(msg: unknown, ...args: unknown[]): void // }