@codeleap/logger 6.3.0 → 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/lib/Logger.d.ts +52 -0
- package/dist/lib/Logger.d.ts.map +1 -0
- package/dist/lib/Slack.d.ts +51 -0
- package/dist/lib/Slack.d.ts.map +1 -0
- package/dist/lib/index.d.ts +2 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/performance/errors.d.ts +16 -0
- package/dist/lib/performance/errors.d.ts.map +1 -0
- package/dist/lib/performance/index.d.ts +31 -0
- package/dist/lib/performance/index.d.ts.map +1 -0
- package/dist/lib/performance/types.d.ts +7 -0
- package/dist/lib/performance/types.d.ts.map +1 -0
- package/dist/types.d.ts +25 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/utils/createLogger.d.ts +40 -0
- package/dist/utils/createLogger.d.ts.map +1 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/package.json +23 -9
- package/src/lib/Logger.ts +49 -20
- package/src/lib/Slack.ts +26 -2
- package/src/lib/performance/errors.ts +6 -1
- package/src/lib/performance/index.ts +22 -8
- package/src/types.ts +0 -8
- package/src/utils/createLogger.ts +26 -0
- package/package.json.bak +0 -31
- package/src/lib/Sentry.ts +0 -62
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,OAAO,CAAA;AACrB,cAAc,SAAS,CAAA;AACvB,cAAc,SAAS,CAAA"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { LoggerConfig } from '../types';
|
|
2
|
+
import { SlackService } from './Slack';
|
|
3
|
+
import { PerformanceService } from './performance';
|
|
4
|
+
/**
|
|
5
|
+
* Base logger class. Logging methods (`info`, `error`, `warn`, `log`, `debug`, `test`) are stubs
|
|
6
|
+
* that must be overridden by the consuming app — calling them before providing an implementation
|
|
7
|
+
* throws. Use {@link createLogger} to produce a concrete instance, then assign it to `logger`.
|
|
8
|
+
*
|
|
9
|
+
* `initialize` must be called once before `patchConsole` or any Slack/perf functionality works.
|
|
10
|
+
*/
|
|
11
|
+
export declare class Logger {
|
|
12
|
+
static initialized: boolean;
|
|
13
|
+
private config;
|
|
14
|
+
slack: SlackService;
|
|
15
|
+
perf: PerformanceService;
|
|
16
|
+
private isIgnored;
|
|
17
|
+
/**
|
|
18
|
+
* Monkey-patches `console.log`, `console.warn`, and `console.error` so that any message
|
|
19
|
+
* matching an entry in `config.Logger.ignoreLogs` is silently dropped.
|
|
20
|
+
*
|
|
21
|
+
* Call this after `initialize`. Patching before initialization has no effect because
|
|
22
|
+
* `isIgnored` returns `false` until the config is loaded.
|
|
23
|
+
*/
|
|
24
|
+
patchConsole(): void;
|
|
25
|
+
/**
|
|
26
|
+
* Bootstraps the logger with app-wide config. Safe to call multiple times — subsequent calls
|
|
27
|
+
* are no-ops. Also instantiates `slack` and `perf` sub-services, so they are only available
|
|
28
|
+
* after this method returns.
|
|
29
|
+
*/
|
|
30
|
+
initialize<T extends LoggerConfig>(config: T): void;
|
|
31
|
+
/**
|
|
32
|
+
* Stub — must be overridden. Intended for temporary test logs that should never reach
|
|
33
|
+
* production; implementations typically no-op in non-dev environments.
|
|
34
|
+
*/
|
|
35
|
+
test(...args: unknown[]): void;
|
|
36
|
+
/** Stub — must be overridden. */
|
|
37
|
+
info(...args: unknown[]): void;
|
|
38
|
+
/** Stub — must be overridden. */
|
|
39
|
+
error(...args: unknown[]): void;
|
|
40
|
+
/** Stub — must be overridden. */
|
|
41
|
+
warn(...args: unknown[]): void;
|
|
42
|
+
/** Stub — must be overridden. */
|
|
43
|
+
log(...args: unknown[]): void;
|
|
44
|
+
/** Stub — must be overridden. */
|
|
45
|
+
debug(...args: unknown[]): void;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Shared `Logger` instance. Logging methods throw until the consuming app replaces them via
|
|
49
|
+
* {@link createLogger} and calls {@link Logger.initialize}.
|
|
50
|
+
*/
|
|
51
|
+
export declare const logger: Logger;
|
|
52
|
+
//# sourceMappingURL=Logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Logger.d.ts","sourceRoot":"","sources":["../../src/lib/Logger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAElD;;;;;;GAMG;AACH,qBAAa,MAAM;IACjB,MAAM,CAAC,WAAW,UAAQ;IAE1B,OAAO,CAAC,MAAM,CAAe;IAE7B,KAAK,EAAG,YAAY,CAAA;IAEpB,IAAI,EAAG,kBAAkB,CAAA;IAEzB,OAAO,CAAC,SAAS;IAMjB;;;;;;OAMG;IACH,YAAY;IAWZ;;;;OAIG;IACH,UAAU,CAAC,CAAC,SAAS,YAAY,EAAE,MAAM,EAAE,CAAC;IAa5C;;;OAGG;IACH,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE;IAIvB,iCAAiC;IACjC,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE;IAIvB,iCAAiC;IACjC,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE;IAIxB,iCAAiC;IACjC,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE;IAIvB,iCAAiC;IACjC,GAAG,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE;IAItB,iCAAiC;IACjC,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE;CAGzB;AAED;;;GAGG;AACH,eAAO,MAAM,MAAM,QAAe,CAAA"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { LoggerConfig } from '../types';
|
|
2
|
+
type EchoSlack = {
|
|
3
|
+
label: string;
|
|
4
|
+
data: object;
|
|
5
|
+
options?: EchoSlackOptions;
|
|
6
|
+
module?: string;
|
|
7
|
+
};
|
|
8
|
+
type OptionInclude = 'version';
|
|
9
|
+
type SendIn = 'debug' | 'release';
|
|
10
|
+
type EchoSlackOptions = {
|
|
11
|
+
sendIn?: SendIn[];
|
|
12
|
+
include?: OptionInclude[];
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Sends structured log messages to a Slack channel via the Slack Web API.
|
|
16
|
+
*
|
|
17
|
+
* The service is inert until {@link setApi} is called with an HTTP client. Messages are
|
|
18
|
+
* silently suppressed when the API client is absent, `echoConfig.enabled` is `false`, or
|
|
19
|
+
* the current environment does not match the caller-supplied `sendIn` filter.
|
|
20
|
+
*/
|
|
21
|
+
export declare class SlackService {
|
|
22
|
+
private config;
|
|
23
|
+
private echoConfig;
|
|
24
|
+
private isDev;
|
|
25
|
+
private appName;
|
|
26
|
+
private api;
|
|
27
|
+
constructor(config: LoggerConfig);
|
|
28
|
+
/**
|
|
29
|
+
* Registers the HTTP client used to POST messages to Slack. Must be called before `echo`
|
|
30
|
+
* can send anything; calling `echo` without a registered API is a no-op.
|
|
31
|
+
*/
|
|
32
|
+
setApi(fetcher: any): void;
|
|
33
|
+
/**
|
|
34
|
+
* Posts a labelled object to Slack. The message is formatted with `util.inspect` so nested
|
|
35
|
+
* structures are human-readable in the channel.
|
|
36
|
+
*
|
|
37
|
+
* Delivery is conditional on three independent guards:
|
|
38
|
+
* - `options.sendIn` — restricts to `'debug'` (IsDev) or `'release'` (production) builds;
|
|
39
|
+
* omitting `sendIn` sends in both environments.
|
|
40
|
+
* - `echoConfig.enabled` — master switch in the config; defaults to `true` when omitted.
|
|
41
|
+
* - A registered API client (see {@link setApi}).
|
|
42
|
+
*
|
|
43
|
+
* Failures are caught and logged to `console.error` rather than propagated.
|
|
44
|
+
*/
|
|
45
|
+
echo(label: EchoSlack['label'], slackData: EchoSlack['data'], moduleName?: EchoSlack['module'], messageOptions?: EchoSlack['options']): Promise<void>;
|
|
46
|
+
private serializers;
|
|
47
|
+
private parseOptions;
|
|
48
|
+
private parseData;
|
|
49
|
+
}
|
|
50
|
+
export {};
|
|
51
|
+
//# sourceMappingURL=Slack.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Slack.d.ts","sourceRoot":"","sources":["../../src/lib/Slack.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAEvC,KAAK,SAAS,GAAG;IACf,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,gBAAgB,CAAA;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,KAAK,aAAa,GAAG,SAAS,CAAA;AAE9B,KAAK,MAAM,GAAG,OAAO,GAAG,SAAS,CAAA;AAEjC,KAAK,gBAAgB,GAAG;IACtB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;IACjB,OAAO,CAAC,EAAE,aAAa,EAAE,CAAA;CAC1B,CAAA;AAMD;;;;;;GAMG;AACH,qBAAa,YAAY;IASX,OAAO,CAAC,MAAM;IAR1B,OAAO,CAAC,UAAU,CAA+B;IAEjD,OAAO,CAAC,KAAK,CAAsC;IAEnD,OAAO,CAAC,OAAO,CAAyB;IAExC,OAAO,CAAC,GAAG,CAAK;gBAEI,MAAM,EAAE,YAAY;IAMxC;;;OAGG;IACH,MAAM,CAAC,OAAO,EAAE,GAAG;IAInB;;;;;;;;;;;OAWG;IACG,IAAI,CACR,KAAK,EAAE,SAAS,CAAC,OAAO,CAAC,EACzB,SAAS,EAAE,SAAS,CAAC,MAAM,CAAC,EAC5B,UAAU,GAAE,SAAS,CAAC,QAAQ,CAAa,EAC3C,cAAc,GAAE,SAAS,CAAC,SAAS,CAAM;IA+B3C,OAAO,CAAC,WAAW,CAIlB;IAED,OAAO,CAAC,YAAY;IA+BpB,OAAO,CAAC,SAAS;CA0BlB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAA"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { InspectRenderOptions } from './types';
|
|
2
|
+
type ErrorArgs = InspectRenderOptions & {
|
|
3
|
+
name: string;
|
|
4
|
+
maxRenders: number;
|
|
5
|
+
};
|
|
6
|
+
type ErrorNames = 'maxRenders';
|
|
7
|
+
/**
|
|
8
|
+
* Thrown by {@link PerformanceService.inspectRender} when a component exceeds its allowed
|
|
9
|
+
* render budget. The error name is always `'Codeleap:Perf'`, making it easy to distinguish
|
|
10
|
+
* from application errors in React error boundaries or crash-reporting tools.
|
|
11
|
+
*/
|
|
12
|
+
export declare class PerformanceError extends Error {
|
|
13
|
+
constructor(errorName: ErrorNames, args: Partial<ErrorArgs>);
|
|
14
|
+
}
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/lib/performance/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAA;AAE9C,KAAK,SAAS,GAAG,oBAAoB,GAAG;IACtC,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,MAAM,CAAA;CACnB,CAAA;AAED,KAAK,UAAU,GAAG,YAAY,CAAA;AAa9B;;;;GAIG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;gBAC7B,SAAS,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,CAAC,SAAS,CAAC;CAI5D"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { InspectRenderOptions } from './types';
|
|
2
|
+
import { LoggerConfig } from '../../types';
|
|
3
|
+
export * from './types';
|
|
4
|
+
/**
|
|
5
|
+
* Dev-only performance utilities. All methods are no-ops in production
|
|
6
|
+
* (`config.Environment.IsDev === false`) or when
|
|
7
|
+
* `config.Logger.performanceInspector.enabled` is `false`.
|
|
8
|
+
*/
|
|
9
|
+
export declare class PerformanceService {
|
|
10
|
+
private config;
|
|
11
|
+
renderCounter: Record<string, number>;
|
|
12
|
+
constructor(config: LoggerConfig);
|
|
13
|
+
/**
|
|
14
|
+
* Tracks render frequency for a component and warns when it exceeds the configured threshold.
|
|
15
|
+
*
|
|
16
|
+
* Call this at the top of a function component body (not inside a hook). By default it also
|
|
17
|
+
* registers mount/unmount effects via `useEffect` — pass `noHooks: true` to skip those when
|
|
18
|
+
* the component cannot accept additional hooks.
|
|
19
|
+
*
|
|
20
|
+
* When the accumulated render count within a `throttleInterval` window exceeds `maxRenders`,
|
|
21
|
+
* the counter resets and a {@link PerformanceError} is thrown (surfacing as a React error
|
|
22
|
+
* boundary hit rather than a silent warning).
|
|
23
|
+
*
|
|
24
|
+
* Components whose names start with any entry in
|
|
25
|
+
* `config.Logger.performanceInspector.blacklist` are silently skipped.
|
|
26
|
+
*
|
|
27
|
+
* Has no effect outside a dev environment or when the inspector is disabled in config.
|
|
28
|
+
*/
|
|
29
|
+
inspectRender: (name: string, options?: InspectRenderOptions) => void;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/performance/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAA;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE1C,cAAc,SAAS,CAAA;AAEvB;;;;GAIG;AACH,qBAAa,kBAAkB;IAGjB,OAAO,CAAC,MAAM;IAF1B,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAK;gBAEtB,MAAM,EAAE,YAAY;IAExC;;;;;;;;;;;;;;;OAeG;IACH,aAAa,GACX,MAAM,MAAM,EACZ,UAAS,oBAIR,UAmDF;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/lib/performance/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,oBAAoB,GAAG;IACjC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,OAAO,CAAC,EAAE,KAAK,GAAG,YAAY,CAAA;IAC9B,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,CAAA"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export type LoggerConfig = {
|
|
2
|
+
AppName: string;
|
|
3
|
+
Environment: {
|
|
4
|
+
IsDev: boolean;
|
|
5
|
+
};
|
|
6
|
+
Slack: {
|
|
7
|
+
echo: {
|
|
8
|
+
channel?: string;
|
|
9
|
+
icon: string;
|
|
10
|
+
token: string;
|
|
11
|
+
baseURL?: string;
|
|
12
|
+
enabled?: boolean;
|
|
13
|
+
options?: Record<string, any>;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
Logger: {
|
|
17
|
+
ignoreLogs: string[];
|
|
18
|
+
performanceInspector: {
|
|
19
|
+
enabled: boolean;
|
|
20
|
+
maxRenders: number;
|
|
21
|
+
blacklist: string[];
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AACA,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,MAAM,CAAA;IAEf,WAAW,EAAE;QACX,KAAK,EAAE,OAAO,CAAA;KACf,CAAA;IAED,KAAK,EAAE;QACL,IAAI,EAAE;YACJ,OAAO,CAAC,EAAE,MAAM,CAAA;YAChB,IAAI,EAAE,MAAM,CAAA;YACZ,KAAK,EAAE,MAAM,CAAA;YACb,OAAO,CAAC,EAAE,MAAM,CAAA;YAChB,OAAO,CAAC,EAAE,OAAO,CAAA;YACjB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;SAC9B,CAAA;KACF,CAAA;IAED,MAAM,EAAE;QACN,UAAU,EAAE,MAAM,EAAE,CAAA;QAEpB,oBAAoB,EAAE;YACpB,OAAO,EAAE,OAAO,CAAA;YAChB,UAAU,EAAE,MAAM,CAAA;YAClB,SAAS,EAAE,MAAM,EAAE,CAAA;SACpB,CAAA;KACF,CAAA;CAEF,CAAA"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
type Level = 'info' | 'debug' | 'error' | 'warn' | 'log';
|
|
2
|
+
export type TransportFunction = (level: Level, ...args: unknown[]) => void;
|
|
3
|
+
type LoggerOptions = {
|
|
4
|
+
transport: TransportFunction[];
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Concrete logger implementation produced by {@link createLogger}. Each log method writes to
|
|
8
|
+
* the native `console` counterpart **and** fans out to every registered transport, so
|
|
9
|
+
* third-party sinks (e.g. Sentry, Datadog) receive the same payload without extra wiring.
|
|
10
|
+
*
|
|
11
|
+
* `test` is intentionally a no-op — it exists as a scratch channel that leaves no output in
|
|
12
|
+
* any environment.
|
|
13
|
+
*
|
|
14
|
+
* Transport functions are shared as a static property, meaning all `CustomLogger` instances
|
|
15
|
+
* created in the same process share the same transport list. Only one call to
|
|
16
|
+
* {@link createLogger} is expected per app.
|
|
17
|
+
*/
|
|
18
|
+
declare class CustomLogger {
|
|
19
|
+
static transport: TransportFunction[];
|
|
20
|
+
static applyTransport(level: Level, ...args: unknown[]): void;
|
|
21
|
+
info(...args: unknown[]): void;
|
|
22
|
+
error(...args: unknown[]): void;
|
|
23
|
+
warn(...args: unknown[]): void;
|
|
24
|
+
/** Intentional no-op. Use as a scratch channel for temporary logs that must not ship. */
|
|
25
|
+
test(...args: unknown[]): void;
|
|
26
|
+
log(...args: unknown[]): void;
|
|
27
|
+
debug(...args: unknown[]): void;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Wires up the transport list and returns a ready-to-use {@link CustomLogger} instance.
|
|
31
|
+
*
|
|
32
|
+
* The returned instance satisfies the logging method contract expected by {@link Logger},
|
|
33
|
+
* so it should be used to replace the stub methods on the shared `logger` singleton after
|
|
34
|
+
* calling `logger.initialize(config)`.
|
|
35
|
+
*
|
|
36
|
+
* Calling this more than once replaces the shared transport list for all existing instances.
|
|
37
|
+
*/
|
|
38
|
+
export declare const createLogger: (options: LoggerOptions) => CustomLogger;
|
|
39
|
+
export {};
|
|
40
|
+
//# sourceMappingURL=createLogger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createLogger.d.ts","sourceRoot":"","sources":["../../src/utils/createLogger.ts"],"names":[],"mappings":"AACA,KAAK,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,CAAA;AAExD,MAAM,MAAM,iBAAiB,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;AAE1E,KAAK,aAAa,GAAG;IACnB,SAAS,EAAE,iBAAiB,EAAE,CAAA;CAC/B,CAAA;AAED;;;;;;;;;;;GAWG;AACH,cAAM,YAAY;IAChB,MAAM,CAAC,SAAS,EAAE,iBAAiB,EAAE,CAAA;IAErC,MAAM,CAAC,cAAc,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE;IAMtD,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE;IAKvB,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE;IAKxB,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE;IAKvB,yFAAyF;IACzF,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE;IAIvB,GAAG,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE;IAKtB,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE;CAIzB;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY,GAAI,SAAS,aAAa,iBAIlD,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codeleap/logger",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.0.0",
|
|
4
4
|
"main": "src/index.ts",
|
|
5
|
+
"types": "dist/index.d.ts",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"source": "./src/index.ts",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"src"
|
|
17
|
+
],
|
|
5
18
|
"license": "UNLICENSED",
|
|
6
19
|
"repository": {
|
|
7
20
|
"url": "https://github.com/codeleap-uk/internal-libs-monorepo.git",
|
|
@@ -9,23 +22,24 @@
|
|
|
9
22
|
"directory": "packages/logger"
|
|
10
23
|
},
|
|
11
24
|
"devDependencies": {
|
|
12
|
-
"@codeleap/types": "
|
|
13
|
-
"@codeleap/utils": "
|
|
14
|
-
"@codeleap/config": "
|
|
25
|
+
"@codeleap/types": "7.0.0",
|
|
26
|
+
"@codeleap/utils": "7.0.0",
|
|
27
|
+
"@codeleap/config": "7.0.0",
|
|
15
28
|
"ts-node-dev": "1.1.8",
|
|
16
29
|
"@sentry/types": "8.40.0"
|
|
17
30
|
},
|
|
18
31
|
"scripts": {
|
|
19
|
-
"build": "
|
|
32
|
+
"build": "tsc --build tsconfig.build.json",
|
|
33
|
+
"typecheck": "bun tsc --noEmit -p ./tsconfig.json"
|
|
20
34
|
},
|
|
21
35
|
"peerDependencies": {
|
|
22
|
-
"@codeleap/types": "
|
|
23
|
-
"@codeleap/utils": "
|
|
24
|
-
"typescript": "
|
|
36
|
+
"@codeleap/types": "7.0.0",
|
|
37
|
+
"@codeleap/utils": "7.0.0",
|
|
38
|
+
"typescript": "6.0.3",
|
|
25
39
|
"react": "19.1.0"
|
|
26
40
|
},
|
|
27
41
|
"dependencies": {
|
|
28
42
|
"util": "0.12.5",
|
|
29
43
|
"url-parse": "^1.5.10"
|
|
30
44
|
}
|
|
31
|
-
}
|
|
45
|
+
}
|
package/src/lib/Logger.ts
CHANGED
|
@@ -1,45 +1,57 @@
|
|
|
1
1
|
import { LoggerConfig } from '../types'
|
|
2
|
-
import { SentryService } from './Sentry'
|
|
3
2
|
import { SlackService } from './Slack'
|
|
4
3
|
import { PerformanceService } from './performance'
|
|
5
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Base logger class. Logging methods (`info`, `error`, `warn`, `log`, `debug`, `test`) are stubs
|
|
7
|
+
* that must be overridden by the consuming app — calling them before providing an implementation
|
|
8
|
+
* throws. Use {@link createLogger} to produce a concrete instance, then assign it to `logger`.
|
|
9
|
+
*
|
|
10
|
+
* `initialize` must be called once before `patchConsole` or any Slack/perf functionality works.
|
|
11
|
+
*/
|
|
6
12
|
export class Logger {
|
|
7
13
|
static initialized = false
|
|
8
14
|
|
|
9
|
-
private config
|
|
15
|
+
private config!: LoggerConfig
|
|
10
16
|
|
|
11
|
-
slack
|
|
17
|
+
slack!: SlackService
|
|
12
18
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
perf: PerformanceService
|
|
16
|
-
|
|
17
|
-
private overrideConsoleMethod(args: unknown[], originalConsole: Console['log']) {
|
|
18
|
-
if (!Logger.initialized) return
|
|
19
|
+
perf!: PerformanceService
|
|
19
20
|
|
|
21
|
+
private isIgnored(args: unknown[]): boolean {
|
|
22
|
+
if (!Logger.initialized) return false
|
|
20
23
|
const ignoreLogs = this.config.Logger.ignoreLogs
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
if (shouldIgnore) return
|
|
24
|
-
|
|
25
|
-
return originalConsole.apply(console, args)
|
|
24
|
+
return typeof args[0] === 'string' && ignoreLogs.some(w => args.join(' ').includes(w))
|
|
26
25
|
}
|
|
27
26
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
/**
|
|
28
|
+
* Monkey-patches `console.log`, `console.warn`, and `console.error` so that any message
|
|
29
|
+
* matching an entry in `config.Logger.ignoreLogs` is silently dropped.
|
|
30
|
+
*
|
|
31
|
+
* Call this after `initialize`. Patching before initialization has no effect because
|
|
32
|
+
* `isIgnored` returns `false` until the config is loaded.
|
|
33
|
+
*/
|
|
34
|
+
patchConsole() {
|
|
35
|
+
const consoles = ['log', 'warn', 'error'] as const
|
|
31
36
|
consoles.forEach(level => {
|
|
32
|
-
const
|
|
33
|
-
|
|
37
|
+
const consoleAny = console as unknown as Record<string, (...args: unknown[]) => void>
|
|
38
|
+
const consoleRef = consoleAny[level].bind(console)
|
|
39
|
+
consoleAny[level] = (...args: unknown[]) => {
|
|
40
|
+
if (!this.isIgnored(args)) consoleRef(...args)
|
|
41
|
+
}
|
|
34
42
|
})
|
|
35
43
|
}
|
|
36
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Bootstraps the logger with app-wide config. Safe to call multiple times — subsequent calls
|
|
47
|
+
* are no-ops. Also instantiates `slack` and `perf` sub-services, so they are only available
|
|
48
|
+
* after this method returns.
|
|
49
|
+
*/
|
|
37
50
|
initialize<T extends LoggerConfig>(config: T) {
|
|
38
51
|
if (Logger.initialized) return
|
|
39
52
|
|
|
40
53
|
this.config = config
|
|
41
54
|
|
|
42
|
-
this.sentry = new SentryService(config)
|
|
43
55
|
|
|
44
56
|
this.slack = new SlackService(config)
|
|
45
57
|
|
|
@@ -48,25 +60,42 @@ export class Logger {
|
|
|
48
60
|
Logger.initialized = true
|
|
49
61
|
}
|
|
50
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Stub — must be overridden. Intended for temporary test logs that should never reach
|
|
65
|
+
* production; implementations typically no-op in non-dev environments.
|
|
66
|
+
*/
|
|
67
|
+
test(...args: unknown[]){
|
|
68
|
+
throw new Error('Logger: implement the method "test"')
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Stub — must be overridden. */
|
|
51
72
|
info(...args: unknown[]) {
|
|
52
73
|
throw new Error('Logger: implement the method "info"')
|
|
53
74
|
}
|
|
54
75
|
|
|
76
|
+
/** Stub — must be overridden. */
|
|
55
77
|
error(...args: unknown[]) {
|
|
56
78
|
throw new Error('Logger: implement the method "error"')
|
|
57
79
|
}
|
|
58
80
|
|
|
81
|
+
/** Stub — must be overridden. */
|
|
59
82
|
warn(...args: unknown[]) {
|
|
60
83
|
throw new Error('Logger: implement the method "warn"')
|
|
61
84
|
}
|
|
62
85
|
|
|
86
|
+
/** Stub — must be overridden. */
|
|
63
87
|
log(...args: unknown[]) {
|
|
64
88
|
throw new Error('Logger: implement the method "log"')
|
|
65
89
|
}
|
|
66
90
|
|
|
91
|
+
/** Stub — must be overridden. */
|
|
67
92
|
debug(...args: unknown[]) {
|
|
68
93
|
throw new Error('Logger: implement the method "debug"')
|
|
69
94
|
}
|
|
70
95
|
}
|
|
71
96
|
|
|
97
|
+
/**
|
|
98
|
+
* Shared `Logger` instance. Logging methods throw until the consuming app replaces them via
|
|
99
|
+
* {@link createLogger} and calls {@link Logger.initialize}.
|
|
100
|
+
*/
|
|
72
101
|
export const logger = new Logger()
|
package/src/lib/Slack.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
1
2
|
import { inspect } from 'util'
|
|
2
3
|
import { TypeGuards } from '@codeleap/types'
|
|
3
4
|
import { LoggerConfig } from '../types'
|
|
@@ -22,6 +23,13 @@ const DEFAULT_CHANNEL = '#_dev_logs'
|
|
|
22
23
|
|
|
23
24
|
const DEFAULT_BASE_URL = 'https://slack.com/api/chat.postMessage'
|
|
24
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Sends structured log messages to a Slack channel via the Slack Web API.
|
|
28
|
+
*
|
|
29
|
+
* The service is inert until {@link setApi} is called with an HTTP client. Messages are
|
|
30
|
+
* silently suppressed when the API client is absent, `echoConfig.enabled` is `false`, or
|
|
31
|
+
* the current environment does not match the caller-supplied `sendIn` filter.
|
|
32
|
+
*/
|
|
25
33
|
export class SlackService {
|
|
26
34
|
private echoConfig: LoggerConfig['Slack']['echo']
|
|
27
35
|
|
|
@@ -29,7 +37,7 @@ export class SlackService {
|
|
|
29
37
|
|
|
30
38
|
private appName: LoggerConfig['AppName']
|
|
31
39
|
|
|
32
|
-
private api
|
|
40
|
+
private api: any
|
|
33
41
|
|
|
34
42
|
constructor(private config: LoggerConfig) {
|
|
35
43
|
this.echoConfig = config.Slack.echo
|
|
@@ -37,14 +45,30 @@ export class SlackService {
|
|
|
37
45
|
this.appName = config.AppName
|
|
38
46
|
}
|
|
39
47
|
|
|
48
|
+
/**
|
|
49
|
+
* Registers the HTTP client used to POST messages to Slack. Must be called before `echo`
|
|
50
|
+
* can send anything; calling `echo` without a registered API is a no-op.
|
|
51
|
+
*/
|
|
40
52
|
setApi(fetcher: any) {
|
|
41
53
|
this.api = fetcher
|
|
42
54
|
}
|
|
43
55
|
|
|
56
|
+
/**
|
|
57
|
+
* Posts a labelled object to Slack. The message is formatted with `util.inspect` so nested
|
|
58
|
+
* structures are human-readable in the channel.
|
|
59
|
+
*
|
|
60
|
+
* Delivery is conditional on three independent guards:
|
|
61
|
+
* - `options.sendIn` — restricts to `'debug'` (IsDev) or `'release'` (production) builds;
|
|
62
|
+
* omitting `sendIn` sends in both environments.
|
|
63
|
+
* - `echoConfig.enabled` — master switch in the config; defaults to `true` when omitted.
|
|
64
|
+
* - A registered API client (see {@link setApi}).
|
|
65
|
+
*
|
|
66
|
+
* Failures are caught and logged to `console.error` rather than propagated.
|
|
67
|
+
*/
|
|
44
68
|
async echo(
|
|
45
69
|
label: EchoSlack['label'],
|
|
46
70
|
slackData: EchoSlack['data'],
|
|
47
|
-
moduleName: EchoSlack['module'] =
|
|
71
|
+
moduleName: EchoSlack['module'] = undefined,
|
|
48
72
|
messageOptions: EchoSlack['options'] = {}
|
|
49
73
|
) {
|
|
50
74
|
const options = this.parseOptions(messageOptions)
|
|
@@ -11,13 +11,18 @@ const defineError = (errorName: ErrorNames, args: Partial<ErrorArgs>) => {
|
|
|
11
11
|
switch (errorName) {
|
|
12
12
|
case 'maxRenders':
|
|
13
13
|
return `${args.name} is rendering more than ${args.maxRenders}time per ${
|
|
14
|
-
args.throttleInterval / 1000
|
|
14
|
+
(args.throttleInterval ?? 0) / 1000
|
|
15
15
|
}second!
|
|
16
16
|
If you aware of this, you can disable it in the Settings.ts > Performancer.
|
|
17
17
|
`
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Thrown by {@link PerformanceService.inspectRender} when a component exceeds its allowed
|
|
23
|
+
* render budget. The error name is always `'Codeleap:Perf'`, making it easy to distinguish
|
|
24
|
+
* from application errors in React error boundaries or crash-reporting tools.
|
|
25
|
+
*/
|
|
21
26
|
export class PerformanceError extends Error {
|
|
22
27
|
constructor(errorName: ErrorNames, args: Partial<ErrorArgs>) {
|
|
23
28
|
super(defineError(errorName, args))
|
|
@@ -6,18 +6,32 @@ import { LoggerConfig } from '../../types'
|
|
|
6
6
|
|
|
7
7
|
export * from './types'
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Dev-only performance utilities. All methods are no-ops in production
|
|
11
|
+
* (`config.Environment.IsDev === false`) or when
|
|
12
|
+
* `config.Logger.performanceInspector.enabled` is `false`.
|
|
13
|
+
*/
|
|
9
14
|
export class PerformanceService {
|
|
10
15
|
renderCounter: Record<string, number> = {}
|
|
11
16
|
|
|
12
17
|
constructor(private config: LoggerConfig) { }
|
|
13
18
|
|
|
14
19
|
/**
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
* Tracks render frequency for a component and warns when it exceeds the configured threshold.
|
|
21
|
+
*
|
|
22
|
+
* Call this at the top of a function component body (not inside a hook). By default it also
|
|
23
|
+
* registers mount/unmount effects via `useEffect` — pass `noHooks: true` to skip those when
|
|
24
|
+
* the component cannot accept additional hooks.
|
|
25
|
+
*
|
|
26
|
+
* When the accumulated render count within a `throttleInterval` window exceeds `maxRenders`,
|
|
27
|
+
* the counter resets and a {@link PerformanceError} is thrown (surfacing as a React error
|
|
28
|
+
* boundary hit rather than a silent warning).
|
|
29
|
+
*
|
|
30
|
+
* Components whose names start with any entry in
|
|
31
|
+
* `config.Logger.performanceInspector.blacklist` are silently skipped.
|
|
32
|
+
*
|
|
33
|
+
* Has no effect outside a dev environment or when the inspector is disabled in config.
|
|
34
|
+
*/
|
|
21
35
|
inspectRender = (
|
|
22
36
|
name: string,
|
|
23
37
|
options: InspectRenderOptions = {
|
|
@@ -67,13 +81,13 @@ export class PerformanceService {
|
|
|
67
81
|
return
|
|
68
82
|
}
|
|
69
83
|
|
|
70
|
-
function logSummary() {
|
|
84
|
+
function logSummary(this: PerformanceService) {
|
|
71
85
|
if (renders <= 0) return
|
|
72
86
|
|
|
73
87
|
console.log(`[PerformanceInspector] Render summary -> ${name}: ${renders}`)
|
|
74
88
|
this.renderCounter[name] = 0
|
|
75
89
|
}
|
|
76
|
-
|
|
90
|
+
// @ts-ignore
|
|
77
91
|
throttle(logSummary, name, throttleInterval)
|
|
78
92
|
}
|
|
79
93
|
}
|
package/src/types.ts
CHANGED
|
@@ -7,6 +7,18 @@ type LoggerOptions = {
|
|
|
7
7
|
transport: TransportFunction[]
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Concrete logger implementation produced by {@link createLogger}. Each log method writes to
|
|
12
|
+
* the native `console` counterpart **and** fans out to every registered transport, so
|
|
13
|
+
* third-party sinks (e.g. Sentry, Datadog) receive the same payload without extra wiring.
|
|
14
|
+
*
|
|
15
|
+
* `test` is intentionally a no-op — it exists as a scratch channel that leaves no output in
|
|
16
|
+
* any environment.
|
|
17
|
+
*
|
|
18
|
+
* Transport functions are shared as a static property, meaning all `CustomLogger` instances
|
|
19
|
+
* created in the same process share the same transport list. Only one call to
|
|
20
|
+
* {@link createLogger} is expected per app.
|
|
21
|
+
*/
|
|
10
22
|
class CustomLogger {
|
|
11
23
|
static transport: TransportFunction[]
|
|
12
24
|
|
|
@@ -31,6 +43,11 @@ class CustomLogger {
|
|
|
31
43
|
CustomLogger.applyTransport('warn', ...args)
|
|
32
44
|
}
|
|
33
45
|
|
|
46
|
+
/** Intentional no-op. Use as a scratch channel for temporary logs that must not ship. */
|
|
47
|
+
test(...args: unknown[]) {
|
|
48
|
+
|
|
49
|
+
}
|
|
50
|
+
|
|
34
51
|
log(...args: unknown[]) {
|
|
35
52
|
console.log(...args)
|
|
36
53
|
CustomLogger.applyTransport('log', ...args)
|
|
@@ -42,6 +59,15 @@ class CustomLogger {
|
|
|
42
59
|
}
|
|
43
60
|
}
|
|
44
61
|
|
|
62
|
+
/**
|
|
63
|
+
* Wires up the transport list and returns a ready-to-use {@link CustomLogger} instance.
|
|
64
|
+
*
|
|
65
|
+
* The returned instance satisfies the logging method contract expected by {@link Logger},
|
|
66
|
+
* so it should be used to replace the stub methods on the shared `logger` singleton after
|
|
67
|
+
* calling `logger.initialize(config)`.
|
|
68
|
+
*
|
|
69
|
+
* Calling this more than once replaces the shared transport list for all existing instances.
|
|
70
|
+
*/
|
|
45
71
|
export const createLogger = (options: LoggerOptions) => {
|
|
46
72
|
CustomLogger.transport = options.transport
|
|
47
73
|
|
package/package.json.bak
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@codeleap/logger",
|
|
3
|
-
"version": "6.3.0",
|
|
4
|
-
"main": "src/index.ts",
|
|
5
|
-
"license": "UNLICENSED",
|
|
6
|
-
"repository": {
|
|
7
|
-
"url": "https://github.com/codeleap-uk/internal-libs-monorepo.git",
|
|
8
|
-
"type": "git",
|
|
9
|
-
"directory": "packages/logger"
|
|
10
|
-
},
|
|
11
|
-
"devDependencies": {
|
|
12
|
-
"@codeleap/types": "workspace:*",
|
|
13
|
-
"@codeleap/utils": "workspace:*",
|
|
14
|
-
"@codeleap/config": "workspace:*",
|
|
15
|
-
"ts-node-dev": "1.1.8",
|
|
16
|
-
"@sentry/types": "8.40.0"
|
|
17
|
-
},
|
|
18
|
-
"scripts": {
|
|
19
|
-
"build": "echo 'No build needed'"
|
|
20
|
-
},
|
|
21
|
-
"peerDependencies": {
|
|
22
|
-
"@codeleap/types": "workspace:*",
|
|
23
|
-
"@codeleap/utils": "workspace:*",
|
|
24
|
-
"typescript": "5.5.2",
|
|
25
|
-
"react": "19.1.0"
|
|
26
|
-
},
|
|
27
|
-
"dependencies": {
|
|
28
|
-
"util": "0.12.5",
|
|
29
|
-
"url-parse": "^1.5.10"
|
|
30
|
-
}
|
|
31
|
-
}
|
package/src/lib/Sentry.ts
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import type { Breadcrumb, ClientOptions, SeverityLevel, Client } from '@sentry/types'
|
|
2
|
-
import { LoggerConfig } from '../types'
|
|
3
|
-
|
|
4
|
-
const SentrySeverityMap: Record<string, SeverityLevel> = {
|
|
5
|
-
debug: 'debug',
|
|
6
|
-
error: 'error',
|
|
7
|
-
info: 'info',
|
|
8
|
-
log: 'log',
|
|
9
|
-
warn: 'warning',
|
|
10
|
-
silent: 'log',
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
type SentryProvider = {
|
|
14
|
-
addBreadcrumb: (args: Breadcrumb) => void
|
|
15
|
-
init(options: ClientOptions): Client
|
|
16
|
-
captureException(err: any): void
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export class SentryService {
|
|
20
|
-
get provider(): SentryProvider {
|
|
21
|
-
return this.config.Sentry.provider
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
private get enabled() {
|
|
25
|
-
return this.config.Sentry.enabled
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
constructor(private config: LoggerConfig) {
|
|
29
|
-
if (config.Sentry.enabled) {
|
|
30
|
-
const initOptions: ClientOptions = {
|
|
31
|
-
dsn: config.Sentry.dsn,
|
|
32
|
-
debug: config.Sentry.debug,
|
|
33
|
-
beforeBreadcrumb: config.Sentry.beforeBreadcrumb,
|
|
34
|
-
integrations: [],
|
|
35
|
-
enabled: this.enabled,
|
|
36
|
-
...config.Sentry.initArgs,
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
this.provider?.init?.(initOptions)
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
captureBreadcrumb(type: string, msg: string, data: any, category = `logger:${type}`) {
|
|
44
|
-
if (!this.enabled) return
|
|
45
|
-
|
|
46
|
-
const sentryArgs: Breadcrumb = {
|
|
47
|
-
message: msg,
|
|
48
|
-
data,
|
|
49
|
-
category,
|
|
50
|
-
level: SentrySeverityMap[type],
|
|
51
|
-
type: '',
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
this.provider.addBreadcrumb(sentryArgs)
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
captureException(err: any) {
|
|
58
|
-
if (!this.enabled) return
|
|
59
|
-
|
|
60
|
-
this.provider.captureException(err)
|
|
61
|
-
}
|
|
62
|
-
}
|