All files / src/logger/implementation level-utils.ts

90% Statements 36/40
94.44% Branches 34/36
100% Functions 4/4
90% Lines 36/40

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185                    47x 2095x 2095x                   224x     1871x 1871x                                                                   47x 4013x   805x     1132x     1087x     72x     297x     415x     75x     57x     73x                     47x         47x                                                       47x 1990x 1787x     1990x 31x     1959x                   47x 69x   1x     15x     16x     1x     4x     29x     1x     1x     1x              
import { exhaustiveCheck } from '../../utils/common/exhaustive-check.ts';
import { terminalFormatter } from '../../utils/common/terminal-formatter.ts';
import type { Logger, LogLevel } from '../definition.ts';
 
/**
 * Checks if a string is a valid LogLevel.
 *
 * @param value The string to check
 * @returns True if the string is a valid LogLevel, false otherwise
 */
export const isLogLevel = (value: unknown): value is LogLevel => {
  const level = value as LogLevel;
  switch (level) {
    case 'trace':
    case 'debug':
    case 'info':
    case 'notice':
    case 'warning':
    case 'error':
    case 'critical':
    case 'alert':
    case 'emergency':
      return true;
 
    default:
      exhaustiveCheck(level);
      return false;
  }
};
 
/**
 * Converts a LogLevel to its corresponding numeric severity value for comparison operations.
 *
 * This function maps each log level to a numeric value according to its severity, with higher numbers representing
 * higher severity (more important) levels. In other words, the return of this function follows this rule: `trace` <
 * `debug` < `info` < `notice` < `warning` < `error` < `critical` < `alert` < `emergency`.
 *
 * Clients should not use the numeric values directly as they may change in the future, but rather use this function to
 * compare levels.
 *
 * @example
 *
 * ```ts
 * import { toLevelSeverity } from 'emitnlog/logger';
 *
 * const errorSeverity = toLevelSeverity('error');
 * const debugSeverity = toLevelSeverity('debug');
 * console.log(`Error is higher: ${errorSeverity > debugSeverity}`); // Outputs: Error is higher: true
 *
 * // Compare severity levels
 * const level: LogLevel = ...
 * if (toLevelSeverity('level') > toLevelSeverity('debug')) {
 *   // Indicates 'level' is more severe than 'debug'
 * }
 * ```
 *
 * @param level The log level to convert to a numeric weight
 * @returns The numeric weight corresponding to the specified log level
 */
 
export const toLevelSeverity = (level: LogLevel): number => {
  switch (level) {
    case 'trace':
      return 2;
 
    case 'debug':
      return 4;
 
    case 'info':
      return 6;
 
    case 'notice':
      return 8;
 
    case 'warning':
      return 10;
 
    case 'error':
      return 12;
 
    case 'critical':
      return 14;
 
    case 'alert':
      return 16;
 
    case 'emergency':
      return 18;
 
    default:
      exhaustiveCheck(level);
      return 0;
  }
};
 
/**
 * The highest severity log level.
 */
export const HIGHEST_SEVERITY_LOG_LEVEL: LogLevel = 'emergency';
 
/**
 * The lowest severity log level.
 */
export const LOWEST_SEVERITY_LOG_LEVEL: LogLevel = 'trace';
 
/**
 * Determines whether a log entry should be emitted based on the configured logger level and the entry's level.
 *
 * This function implements the severity filtering logic of the logger:
 *
 * - When the logger level is 'off', no entries will be emitted
 * - Otherwise, entries are emitted when their level's severity is equal to or greater than the logger's level
 *
 * For example, if the logger's level is set to 'warning', entries with levels 'warning', 'error', 'critical', 'alert',
 * and 'emergency' are emitted, while entries with levels 'notice', 'info', 'debug', and 'trace' are filtered out.
 *
 * @example
 *
 * ```ts
 * // When logger level is 'warning'
 * shouldEmitEntry('warning', 'error'); // Returns true (error entries are emitted)
 * shouldEmitEntry('warning', 'info'); // Returns false (info entries are filtered out)
 *
 * // When logger is turned off
 * shouldEmitEntry('off', 'emergency'); // Returns false (nothing is emitted)
 * ```
 *
 * @param level The current configured level of the logger or 'off'
 * @param entryLevel The severity level of the log entry to be evaluated
 * @returns True if the entry should be emitted, false otherwise
 */
export const shouldEmitEntry = (loggerLevel: Logger | LogLevel | 'off', entryLevel: LogLevel): boolean => {
  if (!isLogLevel(loggerLevel) && loggerLevel !== 'off') {
    loggerLevel = loggerLevel.level;
  }
 
  if (loggerLevel === 'off') {
    return false;
  }
 
  return toLevelSeverity(entryLevel) >= toLevelSeverity(loggerLevel);
};
 
/**
 * Applies color formatting to text based on the specified log level.
 *
 * @param level - The log level to determine appropriate color formatting
 * @param text - The text to be color-formatted
 * @returns The text with appropriate ANSI color formatting for terminal display
 */
export const decorateLogText = (level: LogLevel, text: string): string => {
  switch (level) {
    case 'trace':
      return terminalFormatter.dim(text);
 
    case 'debug':
      return terminalFormatter.dim(text);
 
    case 'info':
      return terminalFormatter.cyan(text);
 
    case 'notice':
      return terminalFormatter.green(text);
 
    case 'warning':
      return terminalFormatter.yellow(text);
 
    case 'error':
      return terminalFormatter.red(text);
 
    case 'critical':
      return terminalFormatter.magenta(text);
 
    case 'alert':
      return terminalFormatter.boldRed(text);
 
    case 'emergency':
      return terminalFormatter.redBackground(text);
 
    default:
      exhaustiveCheck(level);
      return text;
  }
};