Skip to content

Commit

Permalink
feat: useLogger API
Browse files Browse the repository at this point in the history
  • Loading branch information
noomorph committed Nov 28, 2023
1 parent bced9fe commit 0af430a
Show file tree
Hide file tree
Showing 10 changed files with 172 additions and 16 deletions.
32 changes: 28 additions & 4 deletions src/decorator/Bunyamin.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { deflateCategories, mergeCategories } from './categories';
import { isActionable, isError, isObject, isPromiseLike } from '../utils';
import { isSelfDebug } from '../is-debug';
import type { ThreadGroupConfig } from '../streams';
import type { ThreadID } from '../types';
import { isActionable, isError, isObject, isPromiseLike } from '../utils';
import type {
BunyaminLogMethod,
BunyaminConfig,
Expand All @@ -10,6 +11,7 @@ import type {
BunyanLogLevel,
} from './types';
import { MessageStack } from './message-stack';
import { StackTraceError } from './StackTraceError';

export class Bunyamin<Logger extends BunyanLikeLogger = BunyanLikeLogger> {
public readonly fatal = this.#setupLogMethod('fatal');
Expand All @@ -33,7 +35,7 @@ export class Bunyamin<Logger extends BunyanLikeLogger = BunyanLikeLogger> {
this.#fields = undefined;
this.#shared = {
...config,
threadGroups: config.threadGroups ?? [],
loggerPriority: 0,
messageStack: new MessageStack({
noBeginMessage: config.noBeginMessage,
}),
Expand All @@ -44,15 +46,20 @@ export class Bunyamin<Logger extends BunyanLikeLogger = BunyanLikeLogger> {
}
}

/** @deprecated */

Check warning on line 49 in src/decorator/Bunyamin.ts

View workflow job for this annotation

GitHub Actions / Lint

Missing JSDoc @returns declaration
get threadGroups(): ThreadGroupConfig[] {
return this.#shared.threadGroups!;
return [];
}

get logger(): Logger {
return this.#shared.logger;
}

set logger(logger: Logger) {
this.useLogger(logger);
}

useLogger(logger: Logger, priority = 0): void {
if (this.#shared.immutable) {
throw new Error('Cannot change a logger of an immutable instance');
}
Expand All @@ -61,7 +68,23 @@ export class Bunyamin<Logger extends BunyanLikeLogger = BunyanLikeLogger> {
throw new Error('Cannot change a logger of a child instance');
}

this.#shared.logger = logger;
const { stack } = isSelfDebug() ? new StackTraceError() : StackTraceError.empty();
const currentPriority = this.#shared.loggerPriority;
if (priority >= currentPriority) {
this.#shared.loggerPriority = priority;
this.#shared.logger = logger;
stack &&
this.#shared.logger.trace(
{ cat: 'bunyamin' },
`bunyamin logger changed (${priority} >= ${currentPriority}), caller was:\n${stack}`,
);
} else {
stack &&
this.#shared.logger.trace(
{ cat: 'bunyamin' },
`bunyamin logger not changed (${priority} < ${currentPriority}), caller was:\n${stack}`,
);
}
}

child(overrides?: UserFields): Bunyamin<Logger> {
Expand Down Expand Up @@ -226,5 +249,6 @@ type ResolvedFields = UserFields & {
};

type SharedBunyaminConfig<Logger extends BunyanLikeLogger> = BunyaminConfig<Logger> & {
loggerPriority: number;
messageStack: MessageStack;
};
14 changes: 14 additions & 0 deletions src/decorator/StackTraceError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export class StackTraceError extends Error {
constructor() {
super('Providing stack trace below:');
// eslint-disable-next-line unicorn/custom-error-definition
this.name = 'StackTrace';
}

static empty() {
return {
message: '',
stack: '',
};
}
}
3 changes: 2 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ export * from './noopLogger';
export * from './traceEventStream';
export * from './uniteTraceEvents';
export * from './wrapLogger';
export * from './is-debug';
export { isDebug } from './is-debug';

export const bunyamin = realm.bunyamin;
export const nobunyamin = realm.nobunyamin;
export const threadGroups = realm.threadGroups;

export default bunyamin;
2 changes: 2 additions & 0 deletions src/is-debug/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { createIsDebug } from './createIsDebug';

export const isDebug = createIsDebug(process.env.DEBUG || '');

export const isSelfDebug = () => isDebug('bunyamin');
30 changes: 21 additions & 9 deletions src/realm.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,38 @@
import type { BunyanLikeLogger } from './decorator';
import { Bunyamin } from './decorator';
import { noopLogger } from './noopLogger';
import { isSelfDebug } from './is-debug';
import { ThreadGroups } from './thread-groups';

type Realm = {
bunyamin: Bunyamin<BunyanLikeLogger>;
nobunyamin: Bunyamin<BunyanLikeLogger>;
bunyamin: Bunyamin;
nobunyamin: Bunyamin;
threadGroups: ThreadGroups;
};

function create() {
const threadGroups: any[] = [];
const bunyamin = new Bunyamin<BunyanLikeLogger>({ logger: noopLogger(), threadGroups });
const nobunyamin = new Bunyamin<BunyanLikeLogger>({
const selfDebug = isSelfDebug();
const bunyamin = new Bunyamin({ logger: noopLogger() });
const nobunyamin = new Bunyamin({
logger: noopLogger(),
threadGroups,
immutable: true,
});
const threadGroups = new ThreadGroups(bunyamin);

return { bunyamin, nobunyamin };
if (selfDebug) {
bunyamin.trace({ cat: 'bunyamin' }, 'bunyamin global instance created');
}

return { bunyamin, nobunyamin, threadGroups };
}

function getCached(): Realm | undefined {
return (globalThis as any).__BUNYAMIN__;
const result = (globalThis as any).__BUNYAMIN__;

Check warning on line 29 in src/realm.ts

View workflow job for this annotation

GitHub Actions / Lint

Unexpected any. Specify a different type

if (isSelfDebug() && result) {
result.bunyamin.trace({ cat: 'bunyamin' }, 'bunyamin global instance retrieved from cache');
}

return result;
}

function setCached(realm: Realm) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export type TraceEventStreamOptions = {
* running in parallel, and you want to group them together in the trace
* viewer under the same thread name and keep the thread IDs together.
*/
threadGroups?: (string | ThreadGroupConfig)[];
threadGroups?: Iterable<string | ThreadGroupConfig>;
/**
* Default maximum number of concurrent threads in each thread group.
* Must be a positive integer.
Expand Down
2 changes: 1 addition & 1 deletion src/streams/bunyan-trace-event/options/normalizeOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export function normalizeOptions(
options.defaultThreadName = options.defaultThreadName ?? 'Main Thread';
options.maxConcurrency = options.maxConcurrency ?? 100;
options.strict = options.strict ?? false;
options.threadGroups = (options.threadGroups ?? []).map((threadGroup, index) =>
options.threadGroups = [...(options.threadGroups ?? [])].map((threadGroup, index) =>
typeof threadGroup === 'string'
? {
id: threadGroup,
Expand Down
62 changes: 62 additions & 0 deletions src/thread-groups/ThreadGroups.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { beforeEach, describe, expect, jest, it } from '@jest/globals';
import type { ThreadGroups } from './ThreadGroups';
import { wrapLogger } from '../wrapLogger';
import type { Bunyamin } from '../decorator';

describe('ThreadGroups', () => {
let ThreadGroups: new (logger: Bunyamin) => ThreadGroups;
let threadGroups: ThreadGroups;
let isDebug: jest.Mocked<any>;
let logger: Bunyamin;

beforeEach(() => {
jest.mock('../is-debug');
isDebug = jest.requireMock<any>('../is-debug');
ThreadGroups = jest.requireActual<any>('./ThreadGroups').ThreadGroups;
logger = wrapLogger({
trace: jest.fn(),
debug: jest.fn(),
info: jest.fn(),
warn: jest.fn(),
error: jest.fn(),
fatal: jest.fn(),
});
});

describe('in regular mode', () => {
beforeEach(() => {
isDebug.isSelfDebug.mockReturnValue(false);
threadGroups = new ThreadGroups(logger);
});

it('should be empty by default', () => {
expect([...threadGroups]).toEqual([]);
});

it('should add a thread group', () => {
const group = { id: 'foo', displayName: 'Foo' };
threadGroups.add(group);
expect([...threadGroups]).toEqual([group]);
});

it('should not call logger.trace', () => {
expect(logger.logger.trace).not.toHaveBeenCalled();
});
});

describe('in debug mode', () => {
beforeEach(() => {
isDebug.isSelfDebug.mockReturnValue(true);
threadGroups = new ThreadGroups(logger);
});

it('should call logger.trace upon addition', () => {
const group = { id: 'foo', displayName: 'Foo' };
threadGroups.add(group);
expect(logger.logger.trace).toHaveBeenCalledWith(
{ cat: 'bunyamin' },
expect.stringContaining(__filename),
);
});
});
});
40 changes: 40 additions & 0 deletions src/thread-groups/ThreadGroups.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import type { Bunyamin } from '../decorator';
import type { ThreadGroupConfig } from '../streams';
import { isSelfDebug } from '../is-debug';
import { StackTraceError } from '../decorator/StackTraceError';

export class ThreadGroups {
readonly #bunyamin: Bunyamin;
readonly #debugMode = isSelfDebug();
readonly #groups = new Map<string, ThreadGroupConfig>();

constructor(bunyamin: Bunyamin) {
this.#bunyamin = bunyamin;
this.#groups = new Map();
}

add(group: ThreadGroupConfig) {
if (this.#debugMode) {
if (this.#groups.has(group.id)) {
this.#logAddition(group, 'overwritten');
} else {
this.#logAddition(group, 'added');
}
}

this.#groups.set(group.id, group);
return this;
}

[Symbol.iterator]() {
return this.#groups.values();
}

#logAddition(group: ThreadGroupConfig, action: string) {
const { stack } = new StackTraceError();
this.#bunyamin.trace(
{ cat: 'bunyamin' },
`thread group ${action}: ${group.id} (${group.displayName})\n\n${stack}`,
);
}
}
1 change: 1 addition & 0 deletions src/thread-groups/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './ThreadGroups';

0 comments on commit 0af430a

Please sign in to comment.