Skip to content

Commit 7567e91

Browse files
committed
rename lowercaes
1 parent 7f07ab4 commit 7567e91

File tree

4 files changed

+1259
-0
lines changed

4 files changed

+1259
-0
lines changed

packages/logger/src/legacyLogger.ts

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import { Logger, LogLevel } from './logger';
2+
import { shouldLog } from './utils';
3+
4+
// type comes from "@graphql-mesh/types" package, we're copying them over just to avoid including the whole package
5+
export type LazyLoggerMessage = (() => any | any[]) | any;
6+
7+
/** @deprecated Please migrate to using the {@link Logger} instead.*/
8+
export class LegacyLogger {
9+
#logger: Logger;
10+
11+
constructor(logger: Logger) {
12+
this.#logger = logger;
13+
}
14+
15+
static from(logger: Logger): LegacyLogger {
16+
return new LegacyLogger(logger);
17+
}
18+
19+
#log(level: LogLevel, ...[maybeMsgOrArg, ...restArgs]: any[]) {
20+
if (typeof maybeMsgOrArg === 'string') {
21+
if (restArgs.length) {
22+
this.#logger.log(level, restArgs, maybeMsgOrArg);
23+
} else {
24+
this.#logger.log(level, maybeMsgOrArg);
25+
}
26+
} else {
27+
if (restArgs.length) {
28+
this.#logger.log(level, [maybeMsgOrArg, ...restArgs]);
29+
} else {
30+
this.#logger.log(level, maybeMsgOrArg);
31+
}
32+
}
33+
}
34+
35+
log(...args: any[]) {
36+
this.#log('info', ...args);
37+
}
38+
39+
warn(...args: any[]) {
40+
this.#log('warn', ...args);
41+
}
42+
43+
info(...args: any[]) {
44+
this.#log('info', ...args);
45+
}
46+
47+
error(...args: any[]) {
48+
this.#log('error', ...args);
49+
}
50+
51+
debug(...lazyArgs: LazyLoggerMessage[]) {
52+
if (!shouldLog(this.#logger.level, 'debug')) {
53+
// we only return early here because only debug can have lazy logs
54+
return;
55+
}
56+
this.#log('debug', ...handleLazyMessage(lazyArgs));
57+
}
58+
59+
child(name: string | Record<string, string | number>): LegacyLogger {
60+
name =
61+
stringifyName(name) +
62+
// append space if object is strigified to space out the prefix
63+
(typeof name === 'object' ? ' ' : '');
64+
if (this.#logger.prefix === name) {
65+
return this;
66+
}
67+
return LegacyLogger.from(this.#logger.child(name));
68+
}
69+
70+
addPrefix(prefix: string | Record<string, string | number>): LegacyLogger {
71+
prefix = stringifyName(prefix);
72+
if (this.#logger.prefix?.includes(prefix)) {
73+
// TODO: why do we do this?
74+
return this;
75+
}
76+
return LegacyLogger.from(this.#logger.child(prefix));
77+
}
78+
}
79+
80+
function stringifyName(name: string | Record<string, string | number>) {
81+
if (typeof name === 'string' || typeof name === 'number') {
82+
return `${name}`;
83+
}
84+
const names: string[] = [];
85+
for (const [key, value] of Object.entries(name)) {
86+
names.push(`${key}=${value}`);
87+
}
88+
return `${names.join(', ')}`;
89+
}
90+
91+
function handleLazyMessage(lazyArgs: LazyLoggerMessage[]) {
92+
return lazyArgs.flat(Infinity).flatMap((arg) => {
93+
if (typeof arg === 'function') {
94+
return arg();
95+
}
96+
return arg;
97+
});
98+
}

packages/logger/src/logger.ts

Lines changed: 292 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,292 @@
1+
import { DisposableSymbols } from '@whatwg-node/disposablestack';
2+
import fastSafeStringify from 'fast-safe-stringify';
3+
import format from 'quick-format-unescaped';
4+
import {
5+
Attributes,
6+
getEnv,
7+
isPromise,
8+
logLevel,
9+
MaybeLazy,
10+
parseAttrs,
11+
shallowMergeAttributes,
12+
shouldLog,
13+
truthyEnv,
14+
} from './utils';
15+
import { ConsoleLogWriter, JSONLogWriter, LogWriter } from './writers';
16+
17+
export type { Attributes } from './utils';
18+
19+
export type LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error';
20+
21+
export interface LoggerOptions {
22+
/**
23+
* The minimum log level to log.
24+
*
25+
* Providing `false` will disable all logging.
26+
*
27+
* Provided function will always be invoked to get the current log level.
28+
*
29+
* @default env.LOG_LEVEL || env.DEBUG ? 'debug' : 'info'
30+
*/
31+
level?: MaybeLazy<LogLevel | false>;
32+
/** A prefix to include in every log's message. */
33+
prefix?: string;
34+
/**
35+
* The attributes to include in all logs. Is mainly used to pass the parent
36+
* attributes when creating {@link Logger.child child loggers}.
37+
*/
38+
attrs?: Attributes;
39+
/**
40+
* The log writers to use when writing logs.
41+
*
42+
* @default env.LOG_JSON ? [new JSONLogWriter()] : [new ConsoleLogWriter()]
43+
*/
44+
writers?: [LogWriter, ...LogWriter[]];
45+
}
46+
47+
export class Logger implements AsyncDisposable {
48+
#level: MaybeLazy<LogLevel | false>;
49+
#prefix: string | undefined;
50+
#attrs: Attributes | undefined;
51+
#writers: [LogWriter, ...LogWriter[]];
52+
#pendingWrites = new Set<Promise<void>>();
53+
54+
constructor(opts: LoggerOptions = {}) {
55+
let logLevelEnv = getEnv('LOG_LEVEL');
56+
if (logLevelEnv && !(logLevelEnv in logLevel)) {
57+
throw new Error(
58+
`Invalid LOG_LEVEL environment variable "${logLevelEnv}". Must be one of: ${[...Object.keys(logLevel), 'false'].join(', ')}`,
59+
);
60+
}
61+
this.#level =
62+
opts.level ??
63+
(logLevelEnv as LogLevel) ??
64+
(truthyEnv('DEBUG') ? 'debug' : 'info');
65+
this.#prefix = opts.prefix;
66+
this.#attrs = opts.attrs;
67+
this.#writers =
68+
opts.writers ??
69+
(truthyEnv('LOG_JSON')
70+
? [new JSONLogWriter()]
71+
: [new ConsoleLogWriter()]);
72+
}
73+
74+
/** The prefix that's prepended to each log message. */
75+
public get prefix() {
76+
return this.#prefix;
77+
}
78+
79+
/**
80+
* The attributes that are added to each log. If the log itself contains
81+
* attributes with keys existing in {@link attrs}, the log's attributes will
82+
* override.
83+
*/
84+
public get attrs() {
85+
return this.#attrs;
86+
}
87+
88+
/** The current {@link LogLevel} of the logger. You can change the level using the {@link setLevel} method. */
89+
public get level() {
90+
return typeof this.#level === 'function' ? this.#level() : this.#level;
91+
}
92+
93+
/**
94+
* Sets the new {@link LogLevel} of the logger. All subsequent logs, and {@link child child loggers} whose
95+
* level did not change, will respect the new level.
96+
*/
97+
public setLevel(level: MaybeLazy<LogLevel | false>) {
98+
this.#level = level;
99+
}
100+
101+
public write(
102+
level: LogLevel,
103+
attrs: Attributes | null | undefined,
104+
msg: string | null | undefined,
105+
): void {
106+
for (const w of this.#writers) {
107+
const write$ = w.write(level, attrs, msg);
108+
if (isPromise(write$)) {
109+
this.#pendingWrites.add(write$);
110+
write$
111+
.then(() => {
112+
// we remove from pending writes only if the write was successful
113+
this.#pendingWrites.delete(write$);
114+
})
115+
.catch(() => {
116+
// otherwise we keep in the pending write to throw on flush
117+
});
118+
}
119+
}
120+
}
121+
122+
public flush() {
123+
if (this.#pendingWrites.size) {
124+
const errs: unknown[] = [];
125+
return Promise.allSettled(
126+
Array.from(this.#pendingWrites).map((w) =>
127+
w.catch((err) => errs.push(err)),
128+
),
129+
).then(() => {
130+
this.#pendingWrites.clear();
131+
if (errs.length) {
132+
throw new AggregateError(
133+
errs,
134+
`Failed to flush ${errs.length} writes`,
135+
);
136+
}
137+
});
138+
}
139+
return;
140+
}
141+
142+
async [DisposableSymbols.asyncDispose]() {
143+
return this.flush();
144+
}
145+
146+
//
147+
148+
public child(prefix: string): Logger;
149+
public child(attrs: Attributes, prefix?: string): Logger;
150+
public child(prefixOrAttrs: string | Attributes, prefix?: string): Logger {
151+
if (typeof prefixOrAttrs === 'string') {
152+
return new Logger({
153+
level: () => this.level, // inherits the parent level (yet can be changed on child only when using setLevel)
154+
prefix: (this.#prefix || '') + prefixOrAttrs,
155+
attrs: this.#attrs,
156+
writers: this.#writers,
157+
});
158+
}
159+
return new Logger({
160+
level: () => this.level, // inherits the parent level (yet can be changed on child only when using setLevel)
161+
prefix: (this.#prefix || '') + (prefix || '') || undefined,
162+
attrs: shallowMergeAttributes(this.#attrs, prefixOrAttrs),
163+
writers: this.#writers,
164+
});
165+
}
166+
167+
//
168+
169+
public log(level: LogLevel): void;
170+
public log(level: LogLevel, attrs: MaybeLazy<Attributes>): void;
171+
public log(level: LogLevel, msg: string, ...interpol: unknown[]): void;
172+
public log(
173+
level: LogLevel,
174+
attrs: MaybeLazy<Attributes>,
175+
msg: string,
176+
...interpol: unknown[]
177+
): void;
178+
public log(
179+
level: LogLevel,
180+
maybeAttrsOrMsg?: MaybeLazy<Attributes> | string | null | undefined,
181+
...rest: unknown[]
182+
): void {
183+
if (!shouldLog(this.#level, level)) {
184+
return;
185+
}
186+
187+
let msg: string | undefined;
188+
let attrs: MaybeLazy<Attributes> | undefined;
189+
if (typeof maybeAttrsOrMsg === 'string') {
190+
msg = maybeAttrsOrMsg;
191+
} else if (maybeAttrsOrMsg) {
192+
attrs = maybeAttrsOrMsg;
193+
if (typeof rest[0] === 'string') {
194+
// we shift because the "rest" becomes "interpol"
195+
msg = rest.shift() as string;
196+
}
197+
}
198+
199+
if (this.#prefix) {
200+
msg = `${this.#prefix}${msg || ''}`.trim(); // we trim everything because maybe the "msg" is empty
201+
}
202+
203+
attrs = shallowMergeAttributes(parseAttrs(this.#attrs), parseAttrs(attrs));
204+
205+
msg = msg ? format(msg, rest, { stringify: fastSafeStringify }) : msg;
206+
207+
this.write(level, attrs, msg);
208+
if (truthyEnv('LOG_TRACE_LOGS')) {
209+
console.trace('👆');
210+
}
211+
}
212+
213+
public trace(): void;
214+
public trace(attrs: MaybeLazy<Attributes>): void;
215+
public trace(msg: string, ...interpol: unknown[]): void;
216+
public trace(
217+
attrs: MaybeLazy<Attributes>,
218+
msg: string,
219+
...interpol: unknown[]
220+
): void;
221+
public trace(...args: any): void {
222+
this.log(
223+
'trace',
224+
// @ts-expect-error
225+
...args,
226+
);
227+
}
228+
229+
public debug(): void;
230+
public debug(attrs: MaybeLazy<Attributes>): void;
231+
public debug(msg: string, ...interpol: unknown[]): void;
232+
public debug(
233+
attrs: MaybeLazy<Attributes>,
234+
msg: string,
235+
...interpol: unknown[]
236+
): void;
237+
public debug(...args: any): void {
238+
this.log(
239+
'debug',
240+
// @ts-expect-error
241+
...args,
242+
);
243+
}
244+
245+
public info(): void;
246+
public info(attrs: MaybeLazy<Attributes>): void;
247+
public info(msg: string, ...interpol: unknown[]): void;
248+
public info(
249+
attrs: MaybeLazy<Attributes>,
250+
msg: string,
251+
...interpol: unknown[]
252+
): void;
253+
public info(...args: any): void {
254+
this.log(
255+
'info',
256+
// @ts-expect-error
257+
...args,
258+
);
259+
}
260+
261+
public warn(): void;
262+
public warn(attrs: MaybeLazy<Attributes>): void;
263+
public warn(msg: string, ...interpol: unknown[]): void;
264+
public warn(
265+
attrs: MaybeLazy<Attributes>,
266+
msg: string,
267+
...interpol: unknown[]
268+
): void;
269+
public warn(...args: any): void {
270+
this.log(
271+
'warn',
272+
// @ts-expect-error
273+
...args,
274+
);
275+
}
276+
277+
public error(): void;
278+
public error(attrs: MaybeLazy<Attributes>): void;
279+
public error(msg: string, ...interpol: unknown[]): void;
280+
public error(
281+
attrs: MaybeLazy<Attributes>,
282+
msg: string,
283+
...interpol: unknown[]
284+
): void;
285+
public error(...args: any): void {
286+
this.log(
287+
'error',
288+
// @ts-expect-error
289+
...args,
290+
);
291+
}
292+
}

0 commit comments

Comments
 (0)