bunyamin
Version:
Bunyan-based logger for Node.js supporting Trace Event format
1 lines • 104 kB
Source Map (JSON)
{"version":3,"file":"index.mjs","sources":["../src/decorator/categories/deflateCategories.ts","../src/decorator/categories/inflateCategories.ts","../src/decorator/categories/mergeCategories.ts","../src/is-debug/createIsDebug.ts","../src/is-debug/index.ts","../src/utils/flow.ts","../src/utils/isActionable.ts","../src/utils/isError.ts","../src/utils/isPromiseLike.ts","../src/utils/isObject.ts","../src/utils/isUndefined.ts","../src/decorator/message-stack/MessageStack.ts","../src/decorator/StackTraceError.ts","../src/decorator/Bunyamin.ts","../src/noopLogger/noopLogger.ts","../src/thread-groups/ThreadGroups.ts","../src/realm.ts","../src/streams/bunyan-trace-event/threads/ThreadDispatcher.ts","../src/streams/bunyan-trace-event/threads/ThreadGroupDispatcher.ts","../src/streams/bunyan-trace-event/bunyan2trace/bunyan2trace.ts","../src/streams/bunyan-trace-event/StreamEventBuilder.ts","../src/streams/bunyan-trace-event/options/normalizeOptions.ts","../src/streams/bunyan-trace-event/BunyanTraceEventStream.ts","../src/streams/jsonl/jsonlReadFile.ts","../src/streams/jsonl/jsonlWriteFile.ts","../src/streams/trace-merge/resolvers/tree/abstract/ArrayTreeNode.ts","../src/streams/trace-merge/resolvers/tree/abstract/RangeTreeNode.ts","../src/streams/trace-merge/resolvers/tree/concrete/FileNode.ts","../src/streams/trace-merge/resolvers/tree/concrete/PIDNode.ts","../src/streams/trace-merge/resolvers/tree/concrete/RootNode.ts","../src/streams/trace-merge/resolvers/PIDResolver.ts","../src/streams/trace-merge/resolvers/FilePIDResolver.ts","../src/streams/trace-merge/transforms/multisort.ts","../src/streams/trace-merge/transforms/TraceAnalyze.ts","../src/streams/trace-merge/transforms/TraceMerge.ts","../src/streams/trace-merge/traceMerge.ts","../src/traceEventStream.ts","../src/uniteTraceEvents.ts","../src/wrapLogger.ts","../src/index.ts"],"sourcesContent":["export function deflateCategories(cat: unknown): string | undefined {\n if (!cat) {\n return undefined;\n }\n\n if (Array.isArray(cat)) {\n return cat.filter(Boolean).join(',');\n }\n\n return String(cat);\n}\n","export function inflateCategories(cat: unknown): string[] {\n if (!cat) {\n return [];\n }\n\n if (Array.isArray(cat)) {\n return cat;\n }\n\n return String(cat).split(',');\n}\n","import { inflateCategories } from './inflateCategories';\n\nexport function mergeCategories(left: string[] | undefined, right: unknown): string[] | undefined {\n if (!left || !right) {\n if (left) return left;\n if (right) return inflateCategories(right);\n return undefined;\n }\n\n const iright = inflateCategories(right);\n const categories = left ? [...left, ...iright] : iright;\n const uniqueCategories = new Set(categories);\n return [...uniqueCategories.values()];\n}\n","export function createIsDebug(namespaces: string) {\n const skips: RegExp[] = [];\n const names: RegExp[] = [];\n\n for (const part of namespaces.split(/[\\s,]+/)) {\n if (!part) {\n continue;\n }\n\n const destination = part[0] === '-' ? skips : names;\n const pattern = part.replace(/^-/, '').replace(/\\*/g, '.*?');\n destination.push(new RegExp(`^${pattern}$`));\n }\n\n return function isDebug(name: string): boolean {\n // eslint-disable-next-line unicorn/prefer-at\n if (name[name.length - 1] === '*') {\n return true;\n }\n\n if (skips.some((regex) => regex.test(name))) {\n return false;\n }\n\n if (names.some((regex) => regex.test(name))) {\n return true;\n }\n\n return false;\n };\n}\n","import { createIsDebug } from './createIsDebug';\n\nexport const isDebug = createIsDebug(process.env.DEBUG || '');\n\nexport const isSelfDebug = () => isDebug('bunyamin');\n","export function flow<T1, T2, R>(f: (x: T1) => T2, g: (x: T2) => R): (x: T1) => R {\n return (x: T1) => g(f(x));\n}\n","export function isActionable<T>(value: T | (() => T)): value is () => T {\n return typeof value === 'function';\n}\n","export function isError(value: unknown): value is Error {\n return value instanceof Error;\n}\n","export function isPromiseLike(maybePromise: unknown): maybePromise is PromiseLike<unknown> {\n return maybePromise ? typeof (maybePromise as PromiseLike<unknown>).then === 'function' : false;\n}\n","export function isObject(value: unknown): value is object {\n return value ? typeof value === 'object' : false;\n}\n","export function isUndefined(x: unknown): x is undefined {\n return x === undefined;\n}\n","/* eslint-disable @typescript-eslint/no-non-null-assertion */\nimport type { ThreadID } from '../../types';\n\ntype Message = unknown[];\n\nexport type MessageStackOptions = {\n /**\n * A string or any other value to be used as the message when a thread\n * is popped without any message being pushed previously.\n * @default '<no begin message>'\n */\n noBeginMessage?: unknown;\n};\n\nexport class MessageStack {\n readonly #simple = new Map<unknown, Message[]>();\n readonly #complex = new Map<unknown, Map<unknown, Message[]>>();\n readonly #noBeginMessage: Message;\n\n constructor(options: MessageStackOptions = {}) {\n this.#noBeginMessage = [options.noBeginMessage ?? '<no begin message>'];\n }\n\n push(tid: ThreadID | undefined, message: unknown[]): void {\n const stack = this.#ensureStack(tid);\n stack.push(message);\n }\n\n pop(tid: ThreadID | undefined): unknown[] {\n const stack = this.#ensureStack(tid);\n return stack.pop() ?? this.#noBeginMessage;\n }\n\n #ensureStack(tid: ThreadID | undefined): Message[] {\n if (!Array.isArray(tid)) {\n if (!this.#simple.has(tid)) {\n this.#simple.set(tid, []);\n }\n\n return this.#simple.get(tid)!;\n }\n\n const [alias, subtid] = tid;\n if (!this.#complex.has(alias)) {\n this.#complex.set(alias, new Map());\n }\n\n const submap = this.#complex.get(alias)!;\n if (!submap.has(subtid)) {\n submap.set(subtid, []);\n }\n\n return submap.get(subtid)!;\n }\n}\n","export class StackTraceError extends Error {\n constructor() {\n super('Providing stack trace below:');\n // eslint-disable-next-line unicorn/custom-error-definition\n this.name = 'StackTrace';\n }\n\n static empty() {\n return {\n message: '',\n stack: '',\n };\n }\n}\n","import { deflateCategories, mergeCategories } from './categories';\nimport { isSelfDebug } from '../is-debug';\nimport type { ThreadGroupConfig } from '../streams';\nimport type { ThreadID } from '../types';\nimport { flow, isActionable, isError, isObject, isPromiseLike } from '../utils';\nimport type {\n BunyaminConfig,\n BunyaminLogMethod,\n BunyaminLogRecordFields as UserFields,\n BunyanLikeLogger,\n BunyanLogLevel,\n} from './types';\nimport { MessageStack } from './message-stack';\nimport { StackTraceError } from './StackTraceError';\n\nexport class Bunyamin<Logger extends BunyanLikeLogger = BunyanLikeLogger> {\n public readonly fatal = this.#setupLogMethod('fatal');\n public readonly error = this.#setupLogMethod('error');\n public readonly warn = this.#setupLogMethod('warn');\n public readonly info = this.#setupLogMethod('info');\n public readonly debug = this.#setupLogMethod('debug');\n public readonly trace = this.#setupLogMethod('trace');\n\n readonly #fields: PredefinedFields | undefined;\n /**\n * All instances of {@link Bunyamin} must share the same object instance\n */\n readonly #shared: SharedBunyaminConfig<Logger>;\n\n constructor(config: BunyaminConfig<Logger>, fields?: never);\n constructor(shared: unknown, fields?: unknown) {\n if (fields === undefined) {\n const config = shared as BunyaminConfig<Logger>;\n\n this.#fields = undefined;\n this.#shared = {\n ...config,\n loggerPriority: 0,\n messageStack: new MessageStack({\n noBeginMessage: config.noBeginMessage,\n }),\n };\n } else {\n this.#fields = fields as PredefinedFields;\n this.#shared = shared as SharedBunyaminConfig<Logger>;\n }\n }\n\n /** @deprecated */\n get threadGroups(): ThreadGroupConfig[] {\n return [...(this.#shared.threadGroups ?? [])];\n }\n\n get logger(): Logger {\n return this.#shared.logger;\n }\n\n set logger(logger: Logger) {\n this.useLogger(logger);\n }\n\n useLogger(logger: Logger, priority = 0): this {\n this.#assertNotImmutable();\n this.#assertNotChild('useLogger');\n\n const { stack } = isSelfDebug() ? new StackTraceError() : StackTraceError.empty();\n const currentPriority = this.#shared.loggerPriority;\n if (priority >= currentPriority) {\n this.#shared.loggerPriority = priority;\n this.#shared.logger = logger;\n stack &&\n this.#shared.logger.trace(\n { cat: 'bunyamin' },\n `bunyamin logger changed (${priority} >= ${currentPriority}), caller was:\\n${stack}`,\n );\n } else {\n stack &&\n this.#shared.logger.trace(\n { cat: 'bunyamin' },\n `bunyamin logger not changed (${priority} < ${currentPriority}), caller was:\\n${stack}`,\n );\n }\n\n return this;\n }\n\n useTransform(transformFields: Required<BunyaminConfig<Logger>>['transformFields']): this {\n this.#assertNotImmutable();\n this.#assertNotChild('useTransform');\n\n this.#shared.transformFields = this.#shared.transformFields\n ? flow(this.#shared.transformFields, transformFields)\n : transformFields;\n\n return this;\n }\n\n child(overrides?: UserFields): Bunyamin<Logger> {\n const childContext = this.#mergeFields(this.#fields, this.#transformContext(overrides));\n return new Bunyamin(this.#shared, childContext as never);\n }\n\n #setupLogMethod(level: BunyanLogLevel): BunyaminLogMethod {\n const logMethod = this.#instant.bind(this, level);\n\n return Object.assign(logMethod, {\n begin: this.#begin.bind(this, level),\n complete: this.#complete.bind(this, level),\n end: this.#end.bind(this, level),\n }) as BunyaminLogMethod;\n }\n\n #begin(level: BunyanLogLevel, ...arguments_: unknown[]): void {\n const entry = this.#resolveLogEntry('B', arguments_);\n this.#beginInternal(level, entry.fields, entry.message);\n }\n\n #beginInternal(level: BunyanLogLevel, fields: ResolvedFields, message: unknown[]): void {\n this.#shared.messageStack.push(fields.tid, message);\n this.#shared.logger[level](fields, ...message);\n }\n\n #end(level: BunyanLogLevel, ...arguments_: unknown[]): void {\n const entry = this.#resolveLogEntry('E', arguments_);\n this.#endInternal(level, entry.fields, entry.message);\n }\n\n #endInternal(level: BunyanLogLevel, fields: ResolvedFields, customMessage: unknown[]): void {\n const beginMessage = this.#shared.messageStack.pop(fields.tid);\n const message = customMessage.length > 0 ? customMessage : beginMessage;\n\n this.#shared.logger[level](fields, ...(message as unknown[]));\n }\n\n #instant(level: BunyanLogLevel, ...arguments_: unknown[]): void {\n const entry = this.#resolveLogEntry(void 0, arguments_);\n this.#shared.logger[level](entry.fields, ...entry.message);\n }\n\n #complete<T>(\n level: BunyanLogLevel,\n maybeContext: unknown,\n maybeMessage: unknown,\n maybeAction: T | (() => T),\n ): T {\n const action = typeof maybeContext === 'string' ? (maybeMessage as T | (() => T)) : maybeAction;\n const arguments_ = maybeAction === action ? [maybeContext, maybeMessage] : [maybeContext];\n const { fields, message } = this.#resolveLogEntry('B', arguments_);\n\n return this.#completeInternal(level, fields, message, action);\n }\n\n #completeInternal<T>(\n level: BunyanLogLevel,\n fields: ResolvedFields,\n message: unknown[],\n action: T | (() => T),\n ): T {\n const end = (customContext: EndContext) => {\n const endContext = {\n ...this.#transformContext(customContext),\n ph: 'E',\n } as ResolvedFields;\n\n if (fields.tid !== undefined) {\n endContext.tid = fields.tid;\n }\n\n if (fields.level !== undefined) {\n endContext.level = fields.level;\n }\n\n this.#endInternal(level, endContext, []);\n };\n\n let result;\n this.#beginInternal(level, fields, message);\n try {\n result = isActionable(action) ? action() : action;\n\n if (isPromiseLike(result)) {\n result.then(\n () => end({ success: true }),\n (error) => end({ success: false, err: error }),\n );\n } else {\n end({ success: true });\n }\n\n return result;\n } catch (error: unknown) {\n end({ success: false, err: error });\n throw error;\n }\n }\n\n #resolveLogEntry(phase: MaybePhase, arguments_: unknown[]) {\n const userContext = isObject(arguments_[0]) ? (arguments_[0] as MaybeUserFields) : undefined;\n const fields = this.#mergeFields(this.#fields, this.#transformContext(userContext));\n const message: unknown[] =\n userContext === undefined\n ? arguments_\n : isError(arguments_[0]) && arguments_.length === 1\n ? [arguments_[0].message]\n : arguments_.slice(1);\n\n return {\n fields: this.#resolveFields(fields, phase),\n message,\n };\n }\n\n #mergeFields(\n left: PredefinedFields | undefined,\n right: UserFields | undefined,\n ): PredefinedFields {\n const result = {\n ...left,\n ...right,\n };\n\n const cat = mergeCategories(left?.cat, right?.cat);\n if (result.cat !== cat) {\n result.cat = cat;\n }\n\n return result as PredefinedFields;\n }\n\n #transformContext(maybeError: UserFields | Error | undefined): UserFields | undefined {\n const fields: UserFields | undefined = isError(maybeError) ? { err: maybeError } : maybeError;\n return this.#shared.transformFields ? this.#shared.transformFields(fields) : fields;\n }\n\n #resolveFields(fields: PredefinedFields, ph: MaybePhase): ResolvedFields {\n const result: ResolvedFields = fields as ResolvedFields;\n if (ph !== undefined) {\n result.ph = ph as never;\n }\n if (result.cat !== undefined) {\n result.cat = deflateCategories(result.cat);\n }\n return result;\n }\n\n #assertNotChild(methodName: string): void {\n if (this.#fields) {\n throw new Error(`Method Bunyamin#${methodName} is not available for child instances`);\n }\n }\n\n #assertNotImmutable(): void {\n if (this.#shared.immutable) {\n throw new Error('Cannot change a logger of an immutable instance');\n }\n }\n}\n\ntype EndContext = {\n success?: boolean;\n err?: unknown;\n};\n\ntype MaybePhase = 'B' | 'E' | undefined;\n\ntype MaybeUserFields = UserFields | Error;\n\ntype PredefinedFields = UserFields & {\n cat?: string[];\n};\n\ntype ResolvedFields = UserFields & {\n cat?: string;\n ph?: 'B' | 'E';\n tid?: ThreadID;\n /**\n * 10 - trace\n * 20 - debug\n * 30 - info\n * 40 - warn\n * 50 - error\n * 60 - fatal\n */\n level?: number;\n};\n\ntype SharedBunyaminConfig<Logger extends BunyanLikeLogger> = BunyaminConfig<Logger> & {\n loggerPriority: number;\n messageStack: MessageStack;\n};\n","import type { BunyanLikeLogger } from '../decorator';\n\nconst noop: any = () => {\n /* no-op */\n};\n\nexport class NoopLogger implements BunyanLikeLogger {\n fatal = noop;\n error = noop;\n warn = noop;\n info = noop;\n debug = noop;\n trace = noop;\n}\n\nexport function noopLogger(_options?: any) {\n return new NoopLogger();\n}\n","import type { Bunyamin } from '../decorator';\nimport type { ThreadGroupConfig } from '../streams';\nimport { isSelfDebug } from '../is-debug';\nimport { StackTraceError } from '../decorator/StackTraceError';\n\nexport class ThreadGroups implements Iterable<ThreadGroupConfig> {\n readonly #debugMode = isSelfDebug();\n readonly #getBunyamin: () => Bunyamin;\n readonly #groups = new Map<string, ThreadGroupConfig>();\n\n constructor(getBunyamin: () => Bunyamin) {\n this.#getBunyamin = getBunyamin;\n this.#groups = new Map();\n }\n\n add(group: ThreadGroupConfig) {\n if (this.#debugMode) {\n if (this.#groups.has(group.id)) {\n this.#logAddition(group, 'overwritten');\n } else {\n this.#logAddition(group, 'added');\n }\n }\n\n this.#groups.set(group.id, group);\n return this;\n }\n\n [Symbol.iterator]() {\n return this.#groups.values();\n }\n\n #logAddition(group: ThreadGroupConfig, action: string) {\n const { stack } = new StackTraceError();\n this.#getBunyamin().trace(\n { cat: 'bunyamin' },\n `thread group ${action}: ${group.id} (${group.displayName})\\n\\n${stack}`,\n );\n }\n}\n","/* eslint-disable prefer-const */\nimport { Bunyamin } from './decorator';\nimport { noopLogger } from './noopLogger';\nimport { isSelfDebug } from './is-debug';\nimport { ThreadGroups } from './thread-groups';\n\ntype Realm = {\n bunyamin: Bunyamin;\n nobunyamin: Bunyamin;\n threadGroups: ThreadGroups;\n};\n\nfunction create() {\n let bunyamin: Bunyamin;\n let nobunyamin: Bunyamin;\n\n const selfDebug = isSelfDebug();\n const threadGroups = new ThreadGroups(() => bunyamin);\n\n bunyamin = new Bunyamin({\n logger: noopLogger(),\n threadGroups,\n });\n\n nobunyamin = new Bunyamin({\n immutable: true,\n logger: noopLogger(),\n threadGroups,\n });\n\n if (selfDebug) {\n bunyamin.trace({ cat: 'bunyamin' }, 'bunyamin global instance created');\n }\n\n return { bunyamin, nobunyamin, threadGroups };\n}\n\nfunction getCached(): Realm | undefined {\n const result = (globalThis as any).__BUNYAMIN__;\n\n if (isSelfDebug() && result) {\n result.bunyamin.trace({ cat: 'bunyamin' }, 'bunyamin global instance retrieved from cache');\n }\n\n return result;\n}\n\nfunction setCached(realm: Realm) {\n (globalThis as any).__BUNYAMIN__ = realm;\n return realm;\n}\n\nexport default setCached(getCached() ?? create());\n","import { isUndefined } from '../../../utils';\n\nconst NIL = Symbol('NIL');\n\nexport class ThreadDispatcher {\n readonly #stacks: number[] = [];\n readonly #threads: unknown[] = [];\n readonly #countMax: number;\n\n constructor(\n public readonly name: string,\n public readonly strict: boolean,\n public readonly min: number,\n public readonly max: number,\n ) {\n this.#countMax = max - min + 1;\n }\n\n begin(id: unknown = NIL): number | Error {\n const tid = this.#findTID(id);\n if (tid === -1) {\n return this.#error();\n }\n\n this.#threads[tid] = id;\n this.#stacks[tid] = (this.#stacks[tid] || 0) + 1;\n\n return this.#transposeTID(tid);\n }\n\n resolve(id: unknown = NIL): number | Error {\n const tid = this.#findTID(id);\n if (tid === -1) {\n return this.#error();\n }\n\n return this.#transposeTID(tid);\n }\n\n end(id: unknown = NIL): number | Error {\n const tid = this.#findTID(id);\n if (tid === -1) {\n return this.#error();\n }\n\n if (this.#stacks[tid] && --this.#stacks[tid] === 0) {\n delete this.#threads[tid];\n }\n\n return this.#transposeTID(tid);\n }\n\n #findTID(id: unknown): number {\n let tid = this.#threads.indexOf(id);\n if (tid === -1) {\n // Try to find a recently released slot in the array:\n tid = this.#threads.findIndex(isUndefined);\n }\n\n if (tid === -1) {\n tid = this.#threads.length;\n }\n\n return tid < this.#countMax ? tid : -1;\n }\n\n #transposeTID(tid: number): number {\n return this.min + tid;\n }\n\n #error(): number | Error {\n const count = this.#countMax;\n const threads = count > 1 ? `threads` : `thread`;\n\n return this.strict\n ? new Error(`Exceeded limit of ${count} concurrent ${threads} in group \"${this.name}\"`)\n : this.max;\n }\n}\n","import IntervalTree from '@flatten-js/interval-tree';\n\nimport type { ThreadAlias, ThreadID } from '../../../types';\nimport { ThreadDispatcher } from './ThreadDispatcher';\nimport type { ThreadGroupConfig } from './ThreadGroupConfig';\n\nexport type ThreadGroupDispatcherConfig = {\n defaultThreadName: string;\n maxConcurrency: number;\n strict: boolean;\n threadGroups: Iterable<ThreadGroupConfig>;\n};\n\nexport class ThreadGroupDispatcher {\n readonly #strict: boolean;\n readonly #dispatchers: Record<string, ThreadDispatcher> = {};\n readonly #maxConcurrency: number;\n readonly #defaultThreadName: string;\n readonly #threadGroups: Iterable<ThreadGroupConfig>;\n readonly #names: IntervalTree = new IntervalTree();\n\n #freeThreadId = 1;\n #initialized = false;\n\n constructor(options: ThreadGroupDispatcherConfig) {\n this.#defaultThreadName = options.defaultThreadName;\n this.#maxConcurrency = options.maxConcurrency;\n this.#strict = options.strict;\n this.#threadGroups = options.threadGroups;\n }\n\n name(tid: number): string | undefined {\n this.#ensureInitialized();\n\n if (tid === 0) {\n return this.#defaultThreadName;\n }\n\n return this.#names.search([tid, tid])[0];\n }\n\n resolve(ph: string | undefined, tid: ThreadID | undefined): number | Error {\n this.#ensureInitialized();\n\n if (tid == null) {\n return 0;\n }\n\n if (typeof tid === 'number') {\n return tid;\n }\n\n const dispatcher = this.#resolveDispatcher(tid as ThreadAlias);\n if (!dispatcher) {\n return new Error(`Unknown thread group \"${this.#resolveAlias(tid)}\"`);\n }\n\n const id = this.#resolveId(tid);\n\n switch (ph) {\n case 'B': {\n return dispatcher.begin(id);\n }\n case 'E': {\n return dispatcher.end(id);\n }\n default: {\n return dispatcher.resolve(id);\n }\n }\n }\n\n #ensureInitialized() {\n if (!this.#initialized) {\n this.#initialized = true;\n\n for (const group of this.#threadGroups) {\n this.#registerThreadGroup(group);\n }\n }\n }\n\n #registerThreadGroup(config: ThreadGroupConfig): this {\n const maxConcurrency = config.maxConcurrency ?? this.#maxConcurrency;\n const min = this.#freeThreadId;\n const max = min + maxConcurrency - 1;\n\n this.#dispatchers[config.id] = new ThreadDispatcher(config.displayName, this.#strict, min, max);\n this.#names.insert([min, max], config.displayName);\n this.#freeThreadId = max + 1;\n\n return this;\n }\n\n #resolveDispatcher(threadAlias: ThreadAlias): ThreadDispatcher | undefined {\n const groupName = typeof threadAlias === 'string' ? threadAlias : threadAlias[0];\n return this.#ensureGroupDispatcher(groupName);\n }\n\n #resolveAlias(threadAlias: ThreadAlias | undefined): unknown {\n return Array.isArray(threadAlias) ? threadAlias[0] : threadAlias;\n }\n\n #resolveId(threadAlias: ThreadAlias | undefined): unknown {\n return threadAlias === undefined || typeof threadAlias === 'string'\n ? undefined\n : threadAlias[1];\n }\n\n #ensureGroupDispatcher(threadGroup: string): ThreadDispatcher | undefined {\n if (!this.#dispatchers[threadGroup] && !this.#strict) {\n this.#registerThreadGroup({ id: threadGroup, displayName: threadGroup });\n }\n\n return this.#dispatchers[threadGroup];\n }\n}\n","/* eslint-disable unicorn/switch-case-braces,unicorn/prevent-abbreviations,@typescript-eslint/no-explicit-any*/\nimport type {\n AsyncEvent,\n CompleteEvent,\n CounterEvent,\n DurationBeginEvent,\n DurationEndEvent,\n Event,\n EventWithStack,\n InstantEvent,\n MetadataEvent,\n} from 'trace-event-lib';\n\n// TODO: optimize args - they will be often empty objects\n\nexport function bunyan2trace(record: any): Event {\n if (!record.ph) {\n return buildFallbackEvent(record);\n }\n\n switch (record.ph) {\n case 'B':\n return buildDurationBeginEvent(record);\n case 'E':\n return buildDurationEndEvent(record);\n case 'i':\n return buildInstantEvent(record);\n case 'b':\n case 'e':\n case 'n':\n return buildAsyncEvent(record);\n case 'X':\n return buildCompleteEvent(record);\n case 'C':\n return buildCounterEvent(record);\n case 'M':\n return buildMetadataEvent(record);\n default:\n return buildFallbackEvent(record);\n }\n}\n\nfunction buildAsyncEvent(record: any): AsyncEvent {\n const event = bunyan2trace(record) as AsyncEvent;\n return moveProperties(event.args!, event, ['id', 'id2', 'scope']);\n}\n\nfunction buildCompleteEvent(record: any): CompleteEvent {\n const event = extractEventWithStack(record) as CompleteEvent;\n return moveProperties(event.args!, event, ['dur', 'tdur', 'esf', 'estack']);\n}\n\nfunction buildCounterEvent(record: any): CounterEvent {\n const event = bunyan2trace(record) as CounterEvent;\n delete event.cat;\n return moveProperties(event.args!, event, ['id']);\n}\n\nfunction buildDurationBeginEvent(record: any): DurationBeginEvent {\n return extractEventWithStack(record) as DurationBeginEvent;\n}\n\nfunction buildDurationEndEvent(record: any): DurationEndEvent {\n const event = extractEventWithStack(record) as DurationEndEvent;\n delete event.name;\n delete event.cat;\n return event;\n}\n\nfunction buildMetadataEvent(record: any): MetadataEvent {\n const event = bunyan2trace(record) as MetadataEvent;\n delete event.cat;\n return event;\n}\n\nfunction buildInstantEvent(record: any): InstantEvent {\n const event = extractEventWithStack(record) as InstantEvent;\n const args = moveProperties(event.args!, event, ['s']);\n if (args.s === 'g' || args.s === 'p') {\n delete event.sf;\n delete event.stack;\n }\n\n return event;\n}\n\nfunction buildFallbackEvent(record: any): InstantEvent {\n const event = buildInstantEvent(record);\n event.ph = 'i';\n return event;\n}\n\nfunction extractTraceEvent(record: any): Event {\n const {\n cat,\n cname,\n ph,\n tts,\n pid,\n tid,\n time,\n msg: name,\n name: _processName,\n hostname: _hostname,\n ...args\n } = record;\n\n const ts = new Date(time).getTime() * 1e3;\n\n return {\n cat,\n cname,\n ph,\n ts,\n tts,\n pid,\n tid,\n name,\n args,\n } as Event;\n}\n\nfunction extractEventWithStack(record: any): EventWithStack {\n const event = extractTraceEvent(record) as EventWithStack;\n return moveProperties(event.args!, event, ['sf', 'stack']);\n}\n\nfunction moveProperties<T extends Record<string, any>>(\n source: Record<string, any>,\n target: T,\n keys: (keyof T)[],\n): T {\n for (const key of keys) {\n if (source[key as string] !== undefined) {\n target[key] = source[key as string];\n delete source[key as string];\n }\n }\n\n return target;\n}\n","import type { Event } from 'trace-event-lib';\nimport * as TEL from 'trace-event-lib';\nimport type { Transform } from 'node:stream';\n\nexport class StreamEventBuilder extends TEL.AbstractEventBuilder {\n constructor(protected readonly stream: Transform) {\n super();\n }\n\n public send(event: Event) {\n this.stream.push(event);\n }\n}\n","import type { ThreadGroupConfig } from '../threads';\nimport type { TraceEventStreamOptions } from './TraceEventStreamOptions';\n\nexport function normalizeOptions(\n options: TraceEventStreamOptions,\n): Required<TraceEventStreamOptions> {\n options.ignoreFields = options.ignoreFields ?? ['v', 'hostname', 'level', 'name'];\n options.defaultThreadName = options.defaultThreadName ?? 'Main Thread';\n options.maxConcurrency = options.maxConcurrency ?? 100;\n options.strict = options.strict ?? false;\n options.threadGroups = Array.isArray(options.threadGroups)\n ? options.threadGroups.map((threadGroup, index) =>\n typeof threadGroup === 'string'\n ? {\n id: threadGroup,\n displayName: threadGroup,\n }\n : validateThreadGroup(threadGroup, index),\n )\n : options.threadGroups ?? [];\n\n if (options.maxConcurrency < 1) {\n throw new Error(`maxConcurrency must be at least 1, got ${options.maxConcurrency}`);\n }\n\n return options as Required<TraceEventStreamOptions>;\n}\n\nfunction validateThreadGroup(threadGroup: ThreadGroupConfig, index: number) {\n if (!threadGroup.id) {\n throw new Error('Missing thread group ID in thread group at index ' + index);\n }\n\n if (threadGroup.maxConcurrency != null) {\n if (threadGroup.maxConcurrency < 1) {\n throw new Error(\n `Max concurrency (${threadGroup.id} -> ${threadGroup.maxConcurrency}) has to be a positive integer`,\n );\n }\n\n if (threadGroup.maxConcurrency > 1e6) {\n throw new Error(\n `Max concurrency (${threadGroup.id} -> ${threadGroup.maxConcurrency}) cannot be greater than 1,000,000`,\n );\n }\n }\n\n return threadGroup;\n}\n","import { Transform } from 'node:stream';\n\nimport { isError } from '../../utils';\n\nimport { ThreadGroupDispatcher } from './threads';\nimport type { ThreadGroupConfig } from './threads';\nimport { bunyan2trace } from './bunyan2trace';\nimport { StreamEventBuilder } from './StreamEventBuilder';\nimport type { TraceEventStreamOptions } from './options/TraceEventStreamOptions';\nimport { normalizeOptions } from './options/normalizeOptions';\n\n// TODO: add tests\nexport class BunyanTraceEventStream extends Transform {\n readonly #knownTids = new Set<number>();\n readonly #threadGroupDispatcher: ThreadGroupDispatcher;\n readonly #builder = new StreamEventBuilder(this);\n readonly #ignoreFields: string[];\n\n #started = false;\n\n constructor(userOptions: TraceEventStreamOptions = {}) {\n super({ objectMode: true });\n\n const options = normalizeOptions(userOptions);\n this.#ignoreFields = options.ignoreFields;\n this.#threadGroupDispatcher = new ThreadGroupDispatcher({\n strict: options.strict ?? false,\n defaultThreadName: options.defaultThreadName ?? 'Main Thread',\n maxConcurrency: options.maxConcurrency ?? 100,\n // Lazy to add a `NormalizedOptions...` type, so we just cast it here.\n threadGroups: options.threadGroups as Iterable<ThreadGroupConfig>,\n });\n }\n\n _transform(\n record: unknown,\n _encoding: string,\n callback: (error?: Error | null, data?: unknown) => void,\n ) {\n const json = typeof record === 'string' ? JSON.parse(record) : record;\n const event = json && bunyan2trace(json);\n\n if (event.args) {\n for (const field of this.#ignoreFields) {\n delete event.args[field];\n }\n }\n\n if (!this.#started) {\n this.#started = true;\n this.#builder.metadata({\n pid: event.pid,\n ts: event.ts,\n name: 'process_name',\n args: { name: json.name },\n });\n }\n\n const tid = (event.tid = this.#threadGroupDispatcher.resolve(event.ph, event.tid));\n if (isError(tid)) {\n callback(tid);\n return;\n }\n\n if (!this.#knownTids.has(tid)) {\n this.#knownTids.add(tid);\n\n const threadName = this.#threadGroupDispatcher.name(tid);\n if (threadName) {\n this.#builder.metadata({\n pid: event.pid,\n tid: event.tid,\n ts: event.ts,\n name: 'thread_name',\n args: { name: threadName },\n });\n }\n }\n\n this.#builder.send(event);\n callback(null);\n }\n}\n","import fs from 'node:fs';\nimport type { Readable } from 'node:stream';\nimport { Transform } from 'node:stream';\n// eslint-disable-next-line import/extensions\nimport StreamArray from 'stream-json/streamers/StreamArray.js';\n\nexport function jsonlReadFile(filePath: string): Readable {\n return fs\n .createReadStream(filePath, { encoding: 'utf8' })\n .pipe(StreamArray.withParser())\n .pipe(new MapValues(filePath));\n}\n\nclass MapValues extends Transform {\n constructor(protected readonly filePath: string) {\n super({ objectMode: true });\n }\n\n _transform(\n record: any,\n _encoding: string,\n callback: (error?: Error | null, data?: unknown) => void,\n ) {\n this.push({\n ...record,\n filePath: this.filePath,\n } as JSONLEntry);\n\n callback();\n }\n}\n\nexport type JSONLEntry<T = unknown> = {\n filePath: string;\n key: number;\n value: T;\n};\n","import fs from 'node:fs';\nimport { Writable } from 'node:stream';\n\nexport function jsonlWriteFile(filePath: string): Writable {\n return new JSONLFileStream({ filePath });\n}\n\ntype JSONLFileStreamOptions = {\n filePath: string;\n};\n\ntype ErrorCallback = (error?: Error | null) => void;\n\n// Custom writable stream to append JSON objects\nclass JSONLFileStream extends Writable {\n private readonly _filePath: string;\n private _fileDescriptor = Number.NaN;\n private _offset = Number.NaN;\n private _counter = 0;\n\n constructor(options: JSONLFileStreamOptions) {\n super({ objectMode: true });\n\n this._filePath = options.filePath;\n }\n\n _construct(callback: ErrorCallback) {\n this._offset = 0;\n this._fileDescriptor = fs.openSync(this._filePath, 'wx');\n\n const content = Buffer.from('[]\\n');\n fs.write(this._fileDescriptor, content, this._offset, content.length, (error) => {\n if (error) {\n callback(error);\n } else {\n this._offset += 1;\n callback();\n }\n });\n }\n\n _write(chunk: unknown, _: unknown, callback: ErrorCallback) {\n const content =\n this._counter++ > 0 ? `,\\n${JSON.stringify(chunk)}]\\n` : `${JSON.stringify(chunk)}]\\n`;\n const buffer = Buffer.from(content);\n\n fs.write(\n this._fileDescriptor,\n buffer,\n 0,\n buffer.length,\n this._offset,\n (error: Error | null, bytesWritten: number) => {\n if (error) {\n callback(error);\n } else {\n this._offset += bytesWritten - 2;\n callback();\n }\n },\n );\n }\n\n _final(callback: ErrorCallback) {\n fs.close(this._fileDescriptor, callback);\n }\n}\n","import type { LeafNode, TreeNode } from './TreeNode';\n\nexport class ArrayTreeNode<Value = unknown, ChildNode extends LeafNode<any> = LeafNode>\n implements TreeNode<Value, ChildNode>\n{\n index = -1;\n parent?: TreeNode<any, this>;\n\n readonly #children: ChildNode[] = [];\n readonly #map = new Map<unknown, ChildNode>();\n\n constructor(public value: Value) {}\n\n get size() {\n return this.#children.length;\n }\n\n [Symbol.iterator]() {\n return this.#children[Symbol.iterator]();\n }\n\n findByValue(value: unknown): ChildNode | undefined {\n return this.#map.get(value);\n }\n\n appendChild(node: ChildNode): ChildNode {\n node.index = this.size;\n node.parent = this as TreeNode;\n this.#children.push(node);\n this.#map.set(node.value, node);\n return node;\n }\n}\n","import type { LeafNode, TreeNode } from './TreeNode';\n\nexport class RangeTreeNode<Value> implements LeafNode<Value> {\n index = -1;\n parent?: TreeNode<any, this>;\n\n #min = Number.POSITIVE_INFINITY;\n #max = Number.NEGATIVE_INFINITY;\n\n constructor(public value: Value) {}\n\n get min() {\n return this.#min;\n }\n\n get max() {\n return this.#max;\n }\n\n get size() {\n return this.#max - this.#min + 1;\n }\n\n protected add(child: number) {\n if (child < this.#min) {\n this.#min = child;\n }\n if (child > this.#max) {\n this.#max = child;\n }\n }\n}\n","import { RangeTreeNode } from '../abstract';\n\nexport class FileNode extends RangeTreeNode<string> {\n rank?: number;\n offset?: number;\n\n addTID(tid: number): void {\n return super.add(tid);\n }\n\n transpose(tid: number): number {\n if (tid < this.min || tid > this.max) {\n throw new Error(`Value ${tid} not found in range: [${this.min}, ${this.max}]`);\n }\n\n return (this.offset ?? 0) + (tid - this.min);\n }\n}\n","import { ArrayTreeNode } from '../abstract';\nimport { FileNode } from './FileNode';\n\nexport class PIDNode extends ArrayTreeNode<number, FileNode> {\n addFile(file: string): FileNode {\n /* eslint-disable-next-line unicorn/prefer-dom-node-append */\n return this.findByValue(file) ?? this.appendChild(new FileNode(file));\n }\n}\n","import { ArrayTreeNode } from '../abstract';\nimport { PIDNode } from './PIDNode';\n\nexport class RootNode extends ArrayTreeNode<never, PIDNode> {\n constructor() {\n super(undefined as never);\n }\n\n addPID(pid: number): PIDNode {\n /* eslint-disable-next-line unicorn/prefer-dom-node-append */\n return this.findByValue(pid) ?? this.appendChild(new PIDNode(pid));\n }\n\n rank() {\n let index = 0;\n let offset = 0;\n\n for (const pid of this) {\n for (const file of pid) {\n file.rank = index++;\n file.offset = offset;\n offset += file.size;\n }\n }\n }\n}\n","import { RootNode } from './tree';\nimport type { Resolver } from './Resolver';\n\nexport class PIDResolver implements Resolver {\n protected tree = new RootNode();\n\n add(pid: number, _filePath: string, tid: number) {\n this.tree.addPID(pid).addFile('').addTID(tid);\n }\n\n finalize() {\n this.tree.rank();\n }\n\n resolvePid(_filePath: string, pid: number): number {\n return pid;\n }\n\n resolveTid(_filePath: string, pid: number, tid: number): number {\n const $pid = this.tree.findByValue(pid);\n const $file = $pid?.findByValue('');\n return $file?.transpose(tid) ?? Number.NaN;\n }\n}\n","import { PIDResolver } from './PIDResolver';\n\nexport class FilePIDResolver extends PIDResolver {\n add(pid: number, filePath: string, tid: number) {\n this.tree.addPID(pid).addFile(filePath).addTID(tid);\n }\n\n resolvePid(filePath: string, pid: number): number {\n const $pid = this.tree.findByValue(pid);\n const $file = $pid?.findByValue(filePath);\n return ($file?.rank ?? Number.NaN) + 1;\n }\n\n resolveTid(filePath: string, pid: number, tid: number): number {\n const $pid = this.tree.findByValue(pid);\n const $file = $pid?.findByValue(filePath);\n return $file?.transpose(tid) ?? Number.NaN;\n }\n}\n","import type { Readable } from 'node:stream';\nimport type { TraceEvent } from 'trace-event-lib';\nimport multiSortStream from 'multi-sort-stream';\n\nimport type { JSONLEntry } from '../../jsonl';\n\nexport function multisort(streams: Readable[]): Readable {\n return multiSortStream(streams, comparator);\n}\n\nfunction comparator(a: unknown, b: unknown): number {\n const { value: aa } = a as JSONLEntry<TraceEvent>;\n const { value: bb } = b as JSONLEntry<TraceEvent>;\n\n return aa.ts < bb.ts ? -1 : aa.ts > bb.ts ? 1 : 0;\n}\n","import { Writable } from 'node:stream';\nimport type { TraceEvent } from 'trace-event-lib';\nimport type { Resolver } from '../resolvers';\nimport type { JSONLEntry } from '../../jsonl';\n\nexport class TraceAnalyze extends Writable {\n readonly #resolver: Resolver;\n\n constructor(resolver: Resolver) {\n super({\n objectMode: true,\n highWaterMark: Number.MAX_SAFE_INTEGER,\n });\n\n this.#resolver = resolver;\n }\n\n _write(\n chunk: unknown,\n _encoding: string,\n callback: (error?: Error | null, data?: unknown) => void,\n ) {\n const entry = chunk as JSONLEntry<TraceEvent>;\n this.#resolver.add(entry.value.pid, entry.filePath, entry.value.tid);\n callback();\n }\n\n _final(callback: (error?: Error | null) => void) {\n this.#resolver.finalize();\n callback();\n }\n}\n","import { Transform } from 'node:stream';\nimport type { TraceEvent } from 'trace-event-lib';\n\nimport type { Resolver } from '../resolvers';\nimport type { JSONLEntry } from '../../jsonl';\n\nexport class TraceMerge extends Transform {\n readonly #resolverPromise: Promise<Resolver>;\n #resolver?: Resolver;\n\n constructor(resolverPromise: Promise<Resolver>) {\n super({\n objectMode: true,\n highWaterMark: Number.MAX_SAFE_INTEGER,\n });\n\n this.#resolverPromise = resolverPromise;\n }\n\n _transform(\n chunk: unknown,\n _encoding: string,\n callback: (error?: Error | null, data?: unknown) => void,\n ) {\n if (this.#resolver) {\n const entry = chunk as JSONLEntry<TraceEvent>;\n const output = { ...entry.value };\n if (output.pid != null) {\n output.pid = this.#resolver.resolvePid(entry.filePath, entry.value.pid);\n }\n if (output.tid != null) {\n output.tid = this.#resolver.resolveTid(entry.filePath, entry.value.pid, entry.value.tid);\n }\n this.push(output);\n callback();\n } else {\n this.#resolverPromise.then(\n (resolver) => {\n this.#resolver = resolver;\n this._transform(chunk, _encoding, callback);\n },\n (error) => {\n callback(error);\n },\n );\n }\n }\n}\n","import type { Readable } from 'node:stream';\n\nimport { jsonlReadFile } from '../jsonl';\nimport type { Resolver } from './resolvers';\nimport { FilePIDResolver, PIDResolver } from './resolvers';\nimport { multisort, TraceAnalyze, TraceMerge } from './transforms';\n\nexport type TraceMergeOptions = {\n mode: 'pid' | 'fpid';\n};\n\nexport function traceMerge(filePaths: string[], options?: TraceMergeOptions): Readable {\n const streams = filePaths.map((filePath) => jsonlReadFile(filePath));\n const resolver = makeResolver(options);\n const $resolver = makeDeferred<Resolver>();\n const analyze = new TraceAnalyze(resolver)\n .on('error', (error) => $resolver.reject(error))\n .on('finish', () => $resolver.resolve(resolver));\n\n const merge = new TraceMerge($resolver.promise);\n\n const sorted = multisort(streams);\n sorted.pipe(analyze);\n return sorted.pipe(merge);\n}\n\nfunction makeResolver(options?: TraceMergeOptions): Resolver {\n return options?.mode === 'fpid' ? new FilePIDResolver() : new PIDResolver();\n}\n\nfunction makeDeferred<T>() {\n let resolve: (value: T) => void;\n let reject: (reason?: unknown) => void;\n const promise = new Promise<T>((_resolve, _reject) => {\n resolve = _resolve;\n reject = _reject;\n });\n\n return {\n promise: promise,\n resolve: resolve!,\n reject: reject!,\n };\n}\n","import type { Transform } from 'node:stream';\nimport { BunyanTraceEventStream, jsonlWriteFile } from './streams';\nimport type { TraceEventStreamOptions } from './streams';\n\nexport function traceEventStream(\n options: TraceEventStreamOptions & { filePath: string },\n): Transform {\n const jsonl = jsonlWriteFile(options.filePath);\n const stream = new BunyanTraceEventStream(options);\n stream.pipe(jsonl);\n return stream;\n}\n","import type { Readable } from 'node:stream';\nimport type { TraceMergeOptions } from './streams';\nimport { jsonlWriteFile, traceMerge } from './streams';\n\nexport function uniteTraceEvents(sourcePaths: string[], options?: TraceMergeOptions): Readable {\n return traceMerge(sourcePaths, options);\n}\n\nexport async function uniteTraceEventsToFile(\n sourcePaths: string[],\n destinationPath: string,\n options?: TraceMergeOptions,\n) {\n return new Promise((resolve, reject) => {\n uniteTraceEvents(sourcePaths, options)\n .pipe(jsonlWriteFile(destinationPath))\n .on('finish', resolve)\n .on('error', reject);\n });\n}\n","import type { BunyaminConfig, BunyanLikeLogger } from './decorator';\nimport { Bunyamin } from './decorator';\n\nexport * from './decorator/types';\nexport type { Bunyamin } from './decorator';\n\nexport function wrapLogger<Logger extends BunyanLikeLogger>(\n options: BunyaminConfig<Logger>,\n): Bunyamin<Logger>;\nexport function wrapLogger<Logger extends BunyanLikeLogger>(\n logger: Logger,\n options?: Omit<BunyaminConfig<Logger>, 'logger'>,\n): Bunyamin<Logger>;\nexport function wrapLogger<Logger extends BunyanLikeLogger>(\n maybeLogger: any,\n maybeConfig?: unknown,\n): Bunyamin<Logger> {\n const logger = (maybeLogger.logger ?? maybeLogger) as Logger;\n const config = (logger === maybeLogger ? maybeConfig : maybeLogger) as\n | BunyaminConfig<Logger>\n | undefined;\n\n return new Bunyamin({\n ...config,\n logger,\n });\n}\n","import realm from './realm';\n\nexport * from './noopLogger';\nexport * from './traceEventStream';\nexport * from './uniteTraceEvents';\nexport * from './wrapLogger';\nexport { isDebug } from './is-debug';\n\nexport const bunyamin = realm.bunyamin;\nexport const nobunyamin = realm.nobunyamin;\nexport const threadGroups = realm.threadGroups;\n\nexport default bunyamin;\n"],"names":["deflateCategories","cat","undefined","Array","isArray","filter","Boolean","join","String","inflateCategories","split","mergeCategories","left","right","iright","categories","uniqueCategories","Set","values","createIsDebug","namespaces","skips","names","part","destination","pattern","replace","push","RegExp","isDebug","name","length","some","regex","test","process","env","DEBUG","isSelfDebug","flow","f","g","x","isActionable","value","isError","Error","isPromiseLike","maybePromise","then","isObject","isUndefined","MessageStack","constructor","options","_options$noBeginMessa","Object","defineProperty","_ensureStack","_ensureStack2","_simple","writable","Map","_complex","_noBeginMessage","_classPrivateFieldLooseBase","noBeginMessage","tid","message","stack","pop","_stack$pop","has","set","get","alias","subtid","submap","StackTraceError","empty","_fields","_classPrivateFieldLooseKey","_shared","_setupLogMethod","_begin","_beginInternal","_end","_endInternal","_instant","_complete","_completeInternal","_resolveLogEntry","_mergeFields","_transformContext","_resolveFields","_assertNotChild","_assertNotImmutable","Bunyamin","shared","fields","_assertNotImmutable2","_assertNotChild2","_resolveFields2","_transformContext2","_mergeFields2","_resolveLogEntry2","_completeInternal2","_complete2","_instant2","_endInternal2","_end2","_beginInternal2","_begin2","_setupLogMethod2","fatal","error","warn","info","debug","trace","config","loggerPriority","messageStack","threadGroups","_classPrivateFieldLoo","logger","useLogger","priority","currentPriority","useTransform","transformFields","child","overrides","childContext","level","logMethod","bind","assign","begin","complete","end","arguments_","entry","customMessage","beginMessage","maybeContext","maybeMessage","maybeAction","action","customContext","endContext","ph","result","success","err","phase","userContext","slice","maybeError","methodName","immutable","noop","NoopLogger","noopLogger","_options","_debugMode","_getBunyamin","_groups","_logAddition","ThreadGroups","getBunyamin","_logAddition2","add","group","id","Symbol","iterator","displayName","create","bunyamin","nobunyamin","selfDebug","getCached","globalThis","__BUNYAMIN__","setCached","realm","_getCached","NIL","_stacks","_threads","_countMax","_findTID","_transposeTID","_error","ThreadDispatcher","strict","min","max","_error2","_transposeTID2","_findTID2","resolve","indexOf","findIndex","count","threads","_strict","_dispatchers","_maxConcurrency","_defaultThreadName","_threadGroups","_names","_freeThreadId","_initialized","_ensureInitialized","_registerThreadGroup","_resolveDispatcher","_resolveAlias","_resolveId","_ensureGroupDispatcher","ThreadGroupDispatcher","_ensureGroupDispatcher2","_resolveId2","_resolveAlias2","_resolveDispatcher2","_registerThreadGroup2","_ensureInitialized2","IntervalTree","defaultThreadName","maxConcurrency","search","dispatcher","_config$maxConcurrenc","insert","threadAlias","groupName","threadGroup","bunyan2trace","record","buildFallbackEvent","buildDurationBeginEvent","buildDurationEndEvent","buildInstantEvent","buildAsyncEvent","buildCompleteEvent","buildCounterEvent","buildMetadataEvent","event","moveProperties","args","extractEventWithStack","s","sf","extractTraceEvent","cname","tts","pid","time","msg","_processName","hostname","_hostname","ts","Date","getTime","source","target","keys","key","StreamEventBuilder","TEL","AbstractEventBuilder","stream","send","normalizeOptions","_options$ignoreFields","_options$defaultThrea","_options$maxConcurren","_options$strict","_options$threadGroups","ignoreFields","map","index","validateThreadGroup","_knownTids","_threadGroupDispatcher","_builder","_ignoreFields","_started","BunyanTraceEventStream","Transform","userOptions","objectMode","_transform","_encoding","callback","json","JSON","parse","field","metadata","threadName","jsonlReadFile","filePath","fs","createReadStream","encoding","pipe","StreamArray","withParser","MapValues","jsonlWriteFile","JSONLFileStream","Writable","_filePath","_fileDescriptor","Number","NaN","_offset","_counter","_construct","openSync","content","Buffer","from","write","_write","chunk","_","stringify","buffer","bytesWritten","_final","close","ArrayTreeNode","parent","_children","_map","size","findByValue","appendChild","node","RangeTreeNode","_min","POSITIVE_INFINITY","_max","NEGATIVE_INFINITY","FileNode","rank","offset","addTID","transpose","_this$offset","PIDNode","addFile","file","_this$findByValue","RootNode","addPID","PIDResolver","tree","finalize","resolvePid","resolveTid","_$file$transpose","$pid","$file","FilePIDResolver","_$file$rank","multisort","streams","multiSortStream","comparator","a","b","aa","bb","_resolver","TraceAnalyze","resolver","highWaterMark","MAX_SAFE_INTEGER","_resolverPromise","TraceMerge","resolverPromise","output","traceMerge","filePaths","makeResolver","$resolver","makeDeferred","analyze","on","reject","merge","promise","sorted","mode","Promise","_resolve","_reject","traceEventStream","jsonl","uniteTraceEvents","sourcePaths","uniteTraceEventsToFile","destinationPath","wrapLogger","maybeLogger","maybeConfig","_maybeLogger$logger"],"mappings":";;;;;;;;;;;;;;;;AAAM,SAAUA,iBAAiBA,CAACC,GAAY,EAAA;EAC5C,IAAI,CAACA,GAAG,EAAE;AACR,IAAA,OAAOC,SAAS,CAAA;AACjB,GAAA;AAED,EAAA,IAAIC,KAAK,CAACC,OAAO,CAACH,GAAG,CAAC,EAAE;IACtB,OAAOA,GAAG,CAACI,MAAM,CAACC,OAAO,CAAC,CAACC,IAAI,CAAC,GAAG,CAAC,CAAA;AACrC,GAAA;EAED,OAAOC,MAAM,CAACP,GAAG,CAAC,CAAA;AACpB;;ACVM,SAAUQ,iBAAiBA,CAACR,GAAY,EAAA;EAC5C,I