/ shared / logger / src / errorkit / errorkit-logger.ts
errorkit-logger.ts
 1  import type { ErrorHub, ValueOf } from './types';
 2  import type { LoggerFactory, Logger } from '../types';
 3  
 4  /**
 5   * Determines the level of logs to send to sentry.
 6   *
 7   */
 8  export const ERROR_REPORT_LEVEL = {
 9      error: 'error',
10      error_warn: 'error_warn',
11  } as const;
12  
13  type ReportLevel = ValueOf<typeof ERROR_REPORT_LEVEL>;
14  
15  export class ErrorKitLoggerFactory implements LoggerFactory {
16      private readonly errorKit: ErrorHub;
17      private readonly reportLevel: ReportLevel;
18      constructor(errorKit: ErrorHub, reportLevel?: ReportLevel) {
19          this.errorKit = errorKit;
20          this.reportLevel = reportLevel ?? ERROR_REPORT_LEVEL.error;
21      }
22      loggerFor(name: string): Logger {
23          return new ErrorKitLogger(name, this.errorKit, this.reportLevel);
24      }
25  }
26  
27  interface HasToString {
28      toString(): string;
29  }
30  
31  export class ErrorKitLogger implements Logger {
32      private readonly name: string;
33      private readonly errorKit: ErrorHub;
34      private readonly reportLevel: ReportLevel;
35      constructor(name: string, errorKit: ErrorHub, reportLevel: ReportLevel) {
36          this.name = name;
37          this.errorKit = errorKit;
38          this.reportLevel = reportLevel;
39      }
40  
41      private stringifyConsoleArgs(...args: unknown[]): string {
42          return args.reduce((acc: string, val: unknown) => {
43              let tempVal: HasToString;
44              switch (true) {
45                  case val instanceof Error: {
46                      tempVal = (val as unknown as InstanceType<typeof Error>)
47                          .message;
48                      break;
49                  }
50                  case typeof val === 'object': {
51                      try {
52                          tempVal = JSON.stringify(val);
53                      } catch (e) {
54                          tempVal = `failed to stringify ${val}`;
55                      }
56                      break;
57                  }
58                  case typeof val === 'undefined' || val === null: {
59                      tempVal = `${val}`;
60                      break;
61                  }
62                  default: {
63                      tempVal = val as HasToString;
64                  }
65              }
66  
67              return `${acc} ${tempVal.toString()}`;
68          }, `[${this.name}]`) as string;
69      }
70  
71      debug(..._args: unknown[]): string {
72          return '';
73      }
74      info(..._args: unknown[]): string {
75          return '';
76      }
77      warn(...args: unknown[]): string {
78          if (this.reportLevel === ERROR_REPORT_LEVEL.error_warn) {
79              this.errorKit.captureMessage(this.stringifyConsoleArgs(...args));
80          }
81          return '';
82      }
83      error(...args: unknown[]): string {
84          const errors = args.filter((item) => item instanceof Error) as Error[];
85          const message = this.stringifyConsoleArgs(...args);
86  
87          const error = errors.length === 0 ? new Error(message) : errors[0];
88          error.message = message;
89  
90          this.errorKit.captureException(error);
91          return '';
92      }
93  }