All files / app/util user-bound-logging.ts

100% Statements 13/13
83.33% Branches 5/6
100% Functions 3/3
100% Lines 13/13

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                                    1x                                                         476x       476x                   672x     476x 476x 4760x 4760x   2856x           476x               1x       426x     1x  
/**
 * Options for `bindToLog`.
 */
export interface Options {
  /**
   * The default prefix.
   * Will always be added in front of every message.
   */
  prefix?: string;
 
  /**
   * Custom bound args which will always be
   * added after the message but before any other
   * arguments.
   */
  args?: any[]; // eslint-disable-line @typescript-eslint/no-explicit-any
}
 
const defaultOptions = {
  prefix: 'User %d: ',
  args: [] as any[], // eslint-disable-line @typescript-eslint/no-explicit-any
};
 
/**
 * Binds custom default values to the given debug logging function.
 *
 * This is achieved by wrapping the log function and inserting
 * default values and arguments whenever it is called.
 * The default prefix `User %d: ` and the only default
 * added arguments is one number.
 *
 * To minimize any impact this wrapping could have,
 * the returned value gets all properties of the
 * original log function.
 *
 * *There could be a better way to achieve the same
 * result*
 *
 * @param log - The instance of logging function
 * @param options - Options for binding.
 *                  Defaults to `{prefix: 'User %d: ', args: []}`
 * @returns A bound version of the given logging function
 */
function bindToLog(
    log: debug.Debugger,
    options?: Options,
): debug.Debugger {
  options = {
    ...defaultOptions,
    ...options,
  };
  const {prefix, args: boundArgs} = options as Required<Options>;
 
  /**
   * Wraps the logging function.
   * This approach is used to be able to add
   * properties to the returned function.
   * @param formatter - Message
   * @param args - Any additional arguments
   */
  function debug(formatter: any, ...args: any[]) { // eslint-disable-line max-len, @typescript-eslint/no-explicit-any
    log(prefix + formatter, ...boundArgs, ...args);
  }
 
  const props = Object.getOwnPropertyNames(log);
  for (const prop of props) {
    const descriptor = Object.getOwnPropertyDescriptor(log, prop);
    if (descriptor?.writable) {
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      (debug as any)[prop] = (log as any)[prop];
    }
  }
 
  // Because missing attributes are dynamically assigned,
  // typescript doesn't know its correct
  return debug as unknown as debug.Debugger;
}
 
/**
 * Helper function to bind a user to a debugger.
 * @param log - Debugger function
 * @param id  - User ID
 */
export function bindUser(
    log: debug.Debugger,
    id: number,
): ReturnType<typeof bindToLog> {
  return bindToLog(log, {args: [id]});
}
 
export default bindToLog;