Skip to content

Commit

Permalink
feat: Make CWD redaction configurable
Browse files Browse the repository at this point in the history
  • Loading branch information
FoxxMD committed Mar 8, 2024
1 parent 07b1469 commit 5bf88db
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 26 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Features:
* Clean, opinionated log output format powered by [pino-pretty](https://github.com/pinojs/pino-pretty):
* Colorized output when stream is TTY and supports it
* Automatically [serialize passed objects and Errors](#serializing-objects-and-errors), including [Error Cause](https://github.com/tc39/proposal-error-cause)
* Automatically redact current working directory from log output
* [Bring-Your-Own settings](#additional-app-logger-configuration)
* Add or use your own streams/[transports](https://getpino.io/#/docs/transports?id=known-transports) for destinations
* All pino-pretty configs are exposed and extensible
Expand Down Expand Up @@ -193,9 +194,9 @@ export interface FileOptions {
```ts
export interface LoggerAppExtras {
/**
* Additional pino-pretty options that are applied to the built-in console/log streams
* Additional pino-pretty options that are applied to the built-in console/log streams (including CWD redaction)
* */
pretty?: PrettyOptions
pretty?: PrettyOptionsExtra
/**
* Additional logging destinations to use alongside the built-in console/log stream. These can be any created by buildDestination* functions or other Pino Transports
* */
Expand Down
6 changes: 3 additions & 3 deletions src/destinations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
} from "./types.js";
import {DestinationStream, pino, destination} from "pino";
import {build} from "pino-pretty"
import {PRETTY_OPTS_CONSOLE, PRETTY_OPTS_FILE} from "./pretty.js";
import {PRETTY_OPTS_CONSOLE, PRETTY_OPTS_FILE, prettyOptsConsoleFactory, prettyOptsFileFactory} from "./pretty.js";
import {fileOrDirectoryIsWriteable} from "./util.js";
import path from "path";
import {ErrorWithCause} from "pony-cause";
Expand Down Expand Up @@ -94,7 +94,7 @@ export const buildDestinationFile = (level: LogLevel | false, options: FileDesti

return {
level: level,
stream: build({...PRETTY_OPTS_FILE, ...rest, destination: dest})
stream: build({...prettyOptsFileFactory(rest), ...rest, destination: dest})
};
} catch (e: any) {
throw new ErrorWithCause<Error>('WILL NOT write to file due to an error while trying to access the specified directory', {cause: e as Error});
Expand All @@ -109,7 +109,7 @@ export const buildDestinationFile = (level: LogLevel | false, options: FileDesti
export const buildDestinationStream = (level: LogLevel, options: StreamDestination): LogLevelStreamEntry => {
return {
level: level,
stream: build({...PRETTY_OPTS_CONSOLE, ...options})
stream: build({...prettyOptsConsoleFactory(options)})
}
}

Expand Down
6 changes: 5 additions & 1 deletion src/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import {
PRETTY_OPTS_FILE,
//PRETTY_LEVELS,
//PRETTY_LEVELS_STR,
prettyOptsFactory
prettyOptsFactory,
prettyOptsFileFactory,
prettyOptsConsoleFactory
} from "./pretty.js";
import {
buildDestinationStream,
Expand All @@ -24,6 +26,8 @@ export {
//PRETTY_LEVELS_STR,
PRETTY_ISO8601,
prettyOptsFactory,
prettyOptsFileFactory,
prettyOptsConsoleFactory,
buildDestinationStream,
buildDestinationStdout,
buildDestinationStderr,
Expand Down
6 changes: 4 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import {
LogData,
LogLevel,
LOG_LEVELS,
LoggerAppExtras
LoggerAppExtras,
PrettyOptionsExtra
} from './types.js'

import {
Expand All @@ -23,7 +24,8 @@ export type {
LogOptions,
LogData,
LogLevel,
LoggerAppExtras
LoggerAppExtras,
PrettyOptionsExtra
}

export {
Expand Down
51 changes: 36 additions & 15 deletions src/pretty.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,31 @@
import {PrettyOptions} from "pino-pretty";
import {CWD} from "./util.js";
import {PRETTY_COLORS, PRETTY_COLORS_STR, PRETTY_LEVELS, PRETTY_LEVELS_STR} from "./types.js";
import {PRETTY_COLORS, PRETTY_COLORS_STR, PRETTY_LEVELS, PRETTY_LEVELS_STR, PrettyOptionsExtra} from "./types.js";

/**
* Builds the opinionated `@foxxmd/logging` defaults for pino-pretty `PrettyOptions` and merges them with an optional user-provided `PrettyOptions` object
* */
export const prettyOptsFactory = (opts: Omit<PrettyOptions, 'customLevels'> = {}): PrettyOptions => {
export const prettyOptsFactory = (opts: PrettyOptionsExtra = {}): PrettyOptions => {
const {
//customLevels = {},
customColors = {},
redactCwd = true,
...rest
} = opts;

let redactFunc: (content: string) => string;
if(redactCwd) {
redactFunc = (content) => content.replaceAll(CWD, 'CWD');
} else {
redactFunc = (content) => content;
}

return {
messageFormat: (log, messageKey, levelLabel, {colors}) => {
const labels: string[] = log.labels as string[] ?? [];
const leaf = log.leaf as string | undefined;
const nodes = labels;
if (leaf !== null && leaf !== undefined && !nodes.includes(leaf)) {
nodes.push(leaf);
}
const labelContent = nodes.length === 0 ? '' : `${nodes.map((x: string) => colors.blackBright(`[${x}]`)).join(' ')} `;
const msg = (log[messageKey] as string).replaceAll(CWD, 'CWD');
const stackTrace = log.err !== undefined ? `\n${(log.err as any).stack.replaceAll(CWD, 'CWD')}` : '';
const labelContent = labels.length === 0 ? '' : `${labels.map((x: string) => colors.blackBright(`[${x}]`)).join(' ')} `;
const msg = redactFunc((log[messageKey] as string));
const stackTrace = log.err !== undefined ? redactFunc(`\n${(log.err as any).stack}`) : '';
return `${labelContent}${msg}${stackTrace}`;
},
hideObject: false,
Expand Down Expand Up @@ -69,18 +72,36 @@ const buildColors = (userColors: PrettyOptions['customColors'] = {}): PrettyOpti
return colors;
}

const PRETTY_OPTS_CONSOLE_DEFAULTS: PrettyOptions = {sync: true};

/**
* Pre-defined pino-pretty `PrettyOptions` for use with console/stream output
* Generate pino-pretty `PrettyOptions` for use with console/stream output
*
* @source
* */
export const PRETTY_OPTS_CONSOLE: PrettyOptions = prettyOptsFactory({sync: true})
export const prettyOptsConsoleFactory = (opts: PrettyOptionsExtra = {}): PrettyOptions => prettyOptsFactory({...opts, ...PRETTY_OPTS_CONSOLE_DEFAULTS});
/**
* Pre-defined pino-pretty `PrettyOptions` for use with file output
* Pre-defined pino-pretty `PrettyOptions` for use with console/stream output
*
* @source
* */
export const PRETTY_OPTS_FILE: PrettyOptions = prettyOptsFactory({
export const PRETTY_OPTS_CONSOLE: PrettyOptions = prettyOptsConsoleFactory();

const PRETTY_OPTS_FILE_DEFAULTS: PrettyOptions = {
colorize: false,
sync: false,
});
}

/**
* Generate pino-pretty `PrettyOptions` for use with file output
*
* @source
* */
export const prettyOptsFileFactory = (opts: PrettyOptionsExtra = {}): PrettyOptions => prettyOptsFactory({...opts, ...PRETTY_OPTS_FILE_DEFAULTS});

/**
* Pre-defined pino-pretty `PrettyOptions` for use with file output
*
* @source
* */
export const PRETTY_OPTS_FILE: PrettyOptions = prettyOptsFileFactory();
22 changes: 19 additions & 3 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,16 +124,16 @@ export interface FileLogOptionsStrong extends FileLogOptions {

export type FileLogOptionsParsed = (Omit<FileLogOptions, 'file'> & {level: false}) | FileLogOptionsStrong

export type FileDestination = Omit<PrettyOptions, 'destination' | 'sync'> & FileOptionsParsed;
export type StreamDestination = Omit<PrettyOptions, 'destination'> & {destination: number | DestinationStream | NodeJS.WritableStream};
export type FileDestination = Omit<PrettyOptionsExtra, 'destination' | 'sync'> & FileOptionsParsed;
export type StreamDestination = Omit<PrettyOptionsExtra, 'destination'> & {destination: number | DestinationStream | NodeJS.WritableStream};

export type LogOptionsParsed = Omit<Required<LogOptions>, 'file'> & { file: FileLogOptionsParsed }

export interface LoggerAppExtras {
/**
* Additional pino-pretty options that are applied to the built-in console/log streams
* */
pretty?: PrettyOptions
pretty?: PrettyOptionsExtra
/**
* Additional logging destinations to use alongside the built-in console/log stream. These can be any created by `buildDestination*` functions or other [Pino Transports](https://getpino.io/#/docs/transports?id=known-transports)
* */
Expand All @@ -159,6 +159,22 @@ export const CUSTOM_LEVELS: LoggerOptions<"verbose" | "log">['customLevels'] = {
* */
export type PinoLoggerOptions = Omit<LoggerOptions, 'level' | 'mixin' | 'mixinMergeStrategy' | 'customLevels' | 'useOnlyCustomLevels' | 'transport'>

/**
* pino-pretty options and additional options specific to how @foxxmd/logging uses pino-pretty
* */
export interface PrettyOptionsExtra extends Omit<PrettyOptions, 'customLevels'> {
/**
* Control whether the current working directory should be replaced with 'CWD' in log output
*
* Useful for eliminating noisy parent paths that aren't relevant during debugging -- or to protect user privacy.
*
* **NOTE:** Only applies to log message and errors. If you need to redact arbitrary properties you should use pino's [`redact`](https://getpino.io/#/docs/api?id=redact-array-object) or pino-pretty's [`customPrettifiers`](https://github.com/pinojs/pino-pretty?tab=readme-ov-file#options)
*
* @default true
* */
redactCwd?: boolean
}

/**
* Additional levels included in @foxxmd/logging as an object
*
Expand Down

0 comments on commit 5bf88db

Please sign in to comment.