@decaf-ts/logging 0.10.8 → 0.10.10
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/README.md +106 -297
- package/dist/logging.cjs +1 -1
- package/dist/logging.cjs.map +1 -1
- package/dist/logging.js +1 -1
- package/dist/logging.js.map +1 -1
- package/lib/environment.cjs +5 -2
- package/lib/environment.d.ts +1 -0
- package/lib/environment.js.map +1 -1
- package/lib/esm/environment.d.ts +1 -0
- package/lib/esm/environment.js +5 -2
- package/lib/esm/environment.js.map +1 -1
- package/lib/esm/filters/index.d.ts +5 -0
- package/lib/esm/filters/index.js +5 -0
- package/lib/esm/filters/index.js.map +1 -1
- package/lib/esm/index.d.ts +5 -5
- package/lib/esm/index.js +6 -6
- package/lib/esm/index.js.map +1 -1
- package/lib/filters/index.cjs +5 -0
- package/lib/filters/index.d.ts +5 -0
- package/lib/filters/index.js.map +1 -1
- package/lib/index.cjs +6 -6
- package/lib/index.d.ts +5 -5
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,6 +8,16 @@ Decaf’s logging toolkit keeps one fast MiniLogger at the core while exposing a
|
|
|
8
8
|
- Apply filter chains, transports, and adapter-specific features (Pino, Winston, custom factories) through the shared `LoggingConfig` contract.
|
|
9
9
|
- Instrument classes using decorators, `LoggedClass`, and `Logging.because` while StopWatch, text/time utilities, and environment helpers round out the diagnostics surface.
|
|
10
10
|
|
|
11
|
+
### Core Concepts
|
|
12
|
+
|
|
13
|
+
* **`Logging`**: A static class for managing global logging configuration and creating logger instances.
|
|
14
|
+
* **`MiniLogger`**: A lightweight, default logger implementation.
|
|
15
|
+
* **`LoggedClass`**: An abstract base class that provides a pre-configured logger instance to its subclasses.
|
|
16
|
+
* **`LoggedEnvironment`**: A class for managing environment-specific logging configurations.
|
|
17
|
+
* **Decorators**: A set of decorators (`@log`, `@benchmark`, etc.) for easily adding logging and benchmarking to your methods.
|
|
18
|
+
* **Filters and Transports**: A system for filtering sensitive information and transporting logs to different destinations.
|
|
19
|
+
* **Pino and Winston Integration**: Built-in support for two popular logging libraries, Pino and Winston.
|
|
20
|
+
|
|
11
21
|

|
|
12
22
|

|
|
13
23
|

|
|
@@ -37,7 +47,7 @@ Decaf’s logging toolkit keeps one fast MiniLogger at the core while exposing a
|
|
|
37
47
|
|
|
38
48
|
Documentation available [here](https://decaf-ts.github.io/logging/)
|
|
39
49
|
|
|
40
|
-
Minimal size: 6 KB kb gzipped
|
|
50
|
+
Minimal size: 6.1 KB kb gzipped
|
|
41
51
|
|
|
42
52
|
|
|
43
53
|
# Logging Library — Detailed Description
|
|
@@ -115,361 +125,160 @@ Intended usage
|
|
|
115
125
|
- For advanced deployments, swap to WinstonFactory.
|
|
116
126
|
|
|
117
127
|
|
|
118
|
-
# How to Use
|
|
119
|
-
|
|
120
|
-
All snippets import from `@decaf-ts/logging` (swap to a relative path when working inside this repo). Each item below contains a short description, an optional sequence diagram for complex flows, and runnable TypeScript code.
|
|
128
|
+
# How to Use
|
|
121
129
|
|
|
122
|
-
|
|
123
|
-
Description: Initialize `Logging` once (or hydrate `LoggedEnvironment`) to define levels, formatting, colors, transports, and app identifiers that downstream impersonated loggers inherit without per-call overhead.
|
|
130
|
+
This guide provides examples of how to use the main features of the `@decaf-ts/logging` library.
|
|
124
131
|
|
|
125
|
-
|
|
126
|
-
sequenceDiagram
|
|
127
|
-
autonumber
|
|
128
|
-
participant App as App
|
|
129
|
-
participant Env as LoggedEnvironment
|
|
130
|
-
participant Logging as Logging.setConfig
|
|
131
|
-
participant Root as MiniLogger (root)
|
|
132
|
-
App->>Env: Environment.accumulate(defaults)
|
|
133
|
-
Env-->>App: Env proxy (app name, theme, format)
|
|
134
|
-
App->>Logging: setConfig({ level, format, transports })
|
|
135
|
-
Logging->>Root: ensureRoot() memoizes MiniLogger
|
|
136
|
-
```
|
|
132
|
+
## Initial Configuration
|
|
137
133
|
|
|
138
|
-
|
|
139
|
-
import { Logging, LogLevel, DefaultLoggingConfig, LoggedEnvironment } from "@decaf-ts/logging";
|
|
134
|
+
You can set the initial logging configuration using `Logging.setConfig()`.
|
|
140
135
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
app: "InventoryAPI",
|
|
144
|
-
logging: { separator: "•" },
|
|
145
|
-
});
|
|
136
|
+
```typescript
|
|
137
|
+
import { Logging, LogLevel } from '@decaf-ts/logging';
|
|
146
138
|
|
|
147
139
|
Logging.setConfig({
|
|
148
|
-
...DefaultLoggingConfig,
|
|
149
140
|
level: LogLevel.debug,
|
|
150
|
-
verbose: 2,
|
|
151
141
|
style: true,
|
|
152
|
-
|
|
142
|
+
timestamp: true,
|
|
153
143
|
});
|
|
154
|
-
|
|
155
|
-
Logging.info("Boot complete");
|
|
156
|
-
Logging.verbose("Dependency graph built", 1);
|
|
157
|
-
Logging.silly("Deep diagnostics", 3); // ignored because verbose < 3
|
|
158
144
|
```
|
|
159
145
|
|
|
160
|
-
##
|
|
161
|
-
Description: ONE `MiniLogger` instance powers every context. Calls to `.for(...)` return lightweight proxies that temporarily override context/config without allocating new drivers, so a hot path can derive thousands of child loggers without GC churn.
|
|
162
|
-
|
|
163
|
-
```mermaid
|
|
164
|
-
sequenceDiagram
|
|
165
|
-
autonumber
|
|
166
|
-
participant App as App
|
|
167
|
-
participant Logging as Logging.for(...)
|
|
168
|
-
participant Root as MiniLogger (root)
|
|
169
|
-
participant Proxy as Logger Proxy
|
|
170
|
-
App->>Logging: Logging.for("OrderService")
|
|
171
|
-
Logging->>Root: ensureRoot() reuse
|
|
172
|
-
Root-->>Proxy: Proxy bound to ["OrderService"]
|
|
173
|
-
Proxy->>Proxy: `.for("create")` extends context
|
|
174
|
-
Proxy-->>App: Proxy emits create log (no new logger)
|
|
175
|
-
```
|
|
146
|
+
## Impersonation Mechanism
|
|
176
147
|
|
|
177
|
-
|
|
178
|
-
import { Logging, LogLevel, type LoggingConfig } from "@decaf-ts/logging";
|
|
148
|
+
The logging framework uses a proxy-based impersonation mechanism to create child loggers. This provides a significant performance gain by avoiding the need to create new logger instances for each context.
|
|
179
149
|
|
|
180
|
-
|
|
181
|
-
|
|
150
|
+
```typescript
|
|
151
|
+
import { Logging } from '@decaf-ts/logging';
|
|
182
152
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
scoped.info("Validating payload");
|
|
186
|
-
scoped.for("db").debug("Executing UPSERT..."); // reuses the same proxy target
|
|
187
|
-
scoped.clear(); // resets context/config so the proxy can serve the next call
|
|
188
|
-
}
|
|
153
|
+
const rootLogger = Logging.get();
|
|
154
|
+
const childLogger = rootLogger.for('MyClass');
|
|
189
155
|
|
|
190
|
-
|
|
191
|
-
|
|
156
|
+
// childLogger is a proxy that inherits the configuration of rootLogger
|
|
157
|
+
childLogger.info('This is a message from the child logger');
|
|
192
158
|
```
|
|
193
159
|
|
|
194
|
-
##
|
|
195
|
-
Description: Attach `PatternFilter` or custom filters via `LoggingConfig.filters` to redact PII/passwords before formatting. Filters run on the message string after it was rendered in RAW format; JSON output serializes the already-filtered content, so sensitive values disappear in both outputs.
|
|
196
|
-
|
|
197
|
-
```mermaid
|
|
198
|
-
sequenceDiagram
|
|
199
|
-
autonumber
|
|
200
|
-
participant App as App
|
|
201
|
-
participant Proxy as Logger Proxy
|
|
202
|
-
participant Filter as PatternFilter
|
|
203
|
-
participant Console as Transport
|
|
204
|
-
App->>Proxy: log("password=secret")
|
|
205
|
-
Proxy->>Filter: filter(config, message, context)
|
|
206
|
-
Filter-->>Proxy: "password=***"
|
|
207
|
-
Proxy->>Console: emit RAW or JSON string
|
|
208
|
-
```
|
|
160
|
+
## Filters
|
|
209
161
|
|
|
210
|
-
|
|
211
|
-
import { Logging, LogLevel, PatternFilter, type LoggingConfig } from "@decaf-ts/logging";
|
|
162
|
+
Filters allow you to process log messages before they are written. You can use them to filter out sensitive information.
|
|
212
163
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
super(/(password|ssn)=([^&\s]+)/gi, (_full, key) => `${key}=***`);
|
|
216
|
-
}
|
|
217
|
-
}
|
|
164
|
+
```typescript
|
|
165
|
+
import { Logging, PatternFilter } from '@decaf-ts/logging';
|
|
218
166
|
|
|
219
|
-
|
|
167
|
+
// Filter out passwords
|
|
168
|
+
const passwordFilter = new PatternFilter(/password/i, '********');
|
|
220
169
|
Logging.setConfig({
|
|
221
|
-
|
|
222
|
-
filters,
|
|
223
|
-
format: "raw",
|
|
170
|
+
filters: [passwordFilter],
|
|
224
171
|
});
|
|
225
172
|
|
|
226
|
-
const logger = Logging.
|
|
227
|
-
logger.info(
|
|
228
|
-
|
|
229
|
-
Logging.setConfig({ format: "json" });
|
|
230
|
-
logger.info("ssn=123-45-6789"); // JSON payload contains ssn=*** already
|
|
173
|
+
const logger = Logging.get();
|
|
174
|
+
logger.info('User logged in with password: mysecretpassword');
|
|
175
|
+
// Output will be: User logged in with password: ********
|
|
231
176
|
```
|
|
232
177
|
|
|
233
|
-
##
|
|
234
|
-
Description: Supply writable streams via `LoggingConfig.transports` when using adapters (Pino/Winston) to branch logs to files, sockets, or monitoring systems. Each adapter inspects `transports` and builds either a native transport (Winston) or Pino multistream.
|
|
235
|
-
|
|
236
|
-
```mermaid
|
|
237
|
-
sequenceDiagram
|
|
238
|
-
autonumber
|
|
239
|
-
participant App as App
|
|
240
|
-
participant Logging as Logging.setFactory
|
|
241
|
-
participant Adapter as Adapter Logger
|
|
242
|
-
participant Transport as DestinationStream
|
|
243
|
-
App->>Logging: setFactory(WinstonFactory)
|
|
244
|
-
App->>Adapter: Logging.for("Gateway", { transports })
|
|
245
|
-
Adapter->>Transport: write(formatted line)
|
|
246
|
-
```
|
|
178
|
+
## Transports
|
|
247
179
|
|
|
248
|
-
|
|
249
|
-
import fs from "node:fs";
|
|
250
|
-
import { Logging, LogLevel } from "@decaf-ts/logging";
|
|
251
|
-
import { WinstonFactory } from "@decaf-ts/logging/winston/winston";
|
|
252
|
-
import Transport from "winston-transport";
|
|
180
|
+
Transports are responsible for writing log messages to a destination. The library includes a default console transport, and you can create your own.
|
|
253
181
|
|
|
254
|
-
|
|
255
|
-
log(info: any, callback: () => void) {
|
|
256
|
-
fs.appendFileSync("audit.log", `${info.message}\n`);
|
|
257
|
-
callback();
|
|
258
|
-
}
|
|
259
|
-
}
|
|
182
|
+
*Note: The library currently focuses on filters and logger implementation, with transport-like functionality being a feature of the underlying adapters (Pino, Winston).*
|
|
260
183
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
184
|
+
## Pino and Winston Integration
|
|
185
|
+
|
|
186
|
+
The library includes built-in support for Pino and Winston.
|
|
187
|
+
|
|
188
|
+
### Pino
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
import { Logging } from '@decaf-ts/logging';
|
|
192
|
+
import { pino } from 'pino';
|
|
193
|
+
import { PinoLogFactory } from '@decaf-ts/logging/pino';
|
|
266
194
|
|
|
267
|
-
|
|
195
|
+
const pinoInstance = pino();
|
|
196
|
+
Logging.setFactory(new PinoLogFactory(pinoInstance));
|
|
197
|
+
|
|
198
|
+
const logger = Logging.get();
|
|
199
|
+
logger.info('This message will be logged by Pino');
|
|
268
200
|
```
|
|
269
201
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
import
|
|
275
|
-
import {
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
// Pino: reuse an existing driver and call child()
|
|
280
|
-
const sink = pino({ level: "trace", name: "Api" });
|
|
281
|
-
const pinoLogger = new PinoLogger("Api", { level: LogLevel.debug }, sink);
|
|
282
|
-
pinoLogger.child({ context: "handler" }).info("Child context respects config");
|
|
283
|
-
pinoLogger.flush?.();
|
|
284
|
-
|
|
285
|
-
// Register the adapter globally so Logging.for uses it
|
|
286
|
-
Logging.setFactory(PinoFactory);
|
|
287
|
-
Logging.for("BatchJob").debug("Runs through native Pino now");
|
|
288
|
-
|
|
289
|
-
// Winston: pass custom transports or formats through LoggingConfig
|
|
290
|
-
const winstonLogger = new WinstonLogger("Worker", {
|
|
291
|
-
transports: [
|
|
292
|
-
new (WinstonLogger as any).prototype.winston.transports.Console(), // or custom
|
|
293
|
-
],
|
|
294
|
-
correlationId: "cid-1",
|
|
202
|
+
### Winston
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
import { Logging } from '@decaf-ts/logging';
|
|
206
|
+
import * as winston from 'winston';
|
|
207
|
+
import { WinstonLogFactory } from '@decaf-ts/logging/winston';
|
|
208
|
+
|
|
209
|
+
const winstonInstance = winston.createLogger({
|
|
210
|
+
transports: [new winston.transports.Console()],
|
|
295
211
|
});
|
|
296
|
-
|
|
297
|
-
```
|
|
212
|
+
Logging.setFactory(new WinstonLogFactory(winstonInstance));
|
|
298
213
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
```mermaid
|
|
303
|
-
sequenceDiagram
|
|
304
|
-
autonumber
|
|
305
|
-
participant App as App
|
|
306
|
-
participant Env as Environment.accumulate
|
|
307
|
-
participant Proxy as Env Proxy
|
|
308
|
-
participant Runtime as process.env/ENV
|
|
309
|
-
App->>Env: accumulate({ service: { host: "", port: 8080 } })
|
|
310
|
-
Env-->>Proxy: proxy w/ compose-toString keys
|
|
311
|
-
App->>Proxy: proxy.service.host
|
|
312
|
-
Proxy->>Runtime: check SERVICE__HOST
|
|
313
|
-
Runtime-->>Proxy: "api.internal"
|
|
314
|
-
Proxy-->>App: returns runtime override or default
|
|
214
|
+
const logger = Logging.get();
|
|
215
|
+
logger.info('This message will be logged by Winston');
|
|
315
216
|
```
|
|
316
217
|
|
|
317
|
-
|
|
318
|
-
import { Environment, LoggedEnvironment } from "@decaf-ts/logging/environment";
|
|
218
|
+
## `LoggedEnvironment`
|
|
319
219
|
|
|
320
|
-
|
|
321
|
-
const Config = Environment.accumulate({
|
|
322
|
-
service: { host: "", port: 8080 },
|
|
323
|
-
logging: LoggedEnvironment,
|
|
324
|
-
});
|
|
220
|
+
The `LoggedEnvironment` class allows you to manage environment-specific logging configurations.
|
|
325
221
|
|
|
326
|
-
|
|
327
|
-
|
|
222
|
+
```typescript
|
|
223
|
+
import { LoggedEnvironment } from '@decaf-ts/logging';
|
|
328
224
|
|
|
329
|
-
//
|
|
330
|
-
|
|
331
|
-
const serviceHost = runtime.service.host; // throws if missing at runtime
|
|
225
|
+
// Set the application name
|
|
226
|
+
LoggedEnvironment.app = 'MyAwesomeApp';
|
|
332
227
|
|
|
333
|
-
//
|
|
334
|
-
|
|
228
|
+
// Accumulate additional environment configuration
|
|
229
|
+
LoggedEnvironment.accumulate({
|
|
230
|
+
database: {
|
|
231
|
+
host: 'localhost',
|
|
232
|
+
port: 5432,
|
|
233
|
+
},
|
|
234
|
+
});
|
|
335
235
|
```
|
|
336
236
|
|
|
337
|
-
##
|
|
338
|
-
Description: Extend `LoggedClass` to gain a protected `this.log` that’s already scoped to the subclass and works with decorators, impersonation, and adapters.
|
|
237
|
+
## `LoggedClass`
|
|
339
238
|
|
|
340
|
-
|
|
341
|
-
import { LoggedClass, Logging, LogLevel } from "@decaf-ts/logging";
|
|
239
|
+
The `LoggedClass` is an abstract base class that provides a pre-configured logger instance to its subclasses.
|
|
342
240
|
|
|
343
|
-
|
|
241
|
+
```typescript
|
|
242
|
+
import { LoggedClass } from '@decaf-ts/logging';
|
|
344
243
|
|
|
345
|
-
class
|
|
346
|
-
|
|
347
|
-
this.log.info(
|
|
348
|
-
return true;
|
|
244
|
+
class MyService extends LoggedClass {
|
|
245
|
+
doSomething() {
|
|
246
|
+
this.log.info('Doing something...');
|
|
349
247
|
}
|
|
350
248
|
}
|
|
351
249
|
|
|
352
|
-
const
|
|
353
|
-
|
|
250
|
+
const service = new MyService();
|
|
251
|
+
service.doSomething();
|
|
354
252
|
```
|
|
355
253
|
|
|
356
|
-
##
|
|
357
|
-
Description: `StopWatch` uses the highest resolution clock available (browser `performance.now`, Node `process.hrtime.bigint`, or `Date.now`) to measure laps, pause/resume, and report JSON snapshots—useful for the `@benchmark` decorator or manual instrumentation.
|
|
254
|
+
## Decorators
|
|
358
255
|
|
|
359
|
-
|
|
360
|
-
import { StopWatch } from "@decaf-ts/logging/time";
|
|
256
|
+
The library provides a set of decorators for easily adding logging and benchmarking to your methods.
|
|
361
257
|
|
|
362
|
-
|
|
363
|
-
await new Promise((r) => setTimeout(r, 15));
|
|
364
|
-
sw.lap("load config");
|
|
365
|
-
sw.pause();
|
|
258
|
+
### `@log`
|
|
366
259
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
await new Promise((r) => setTimeout(r, 10));
|
|
370
|
-
const lap = sw.lap("connect db");
|
|
371
|
-
console.log(lap.ms, lap.totalMs, sw.toString());
|
|
372
|
-
console.log(JSON.stringify(sw));
|
|
373
|
-
```
|
|
374
|
-
|
|
375
|
-
## 9. Decorators & Advanced Instrumentation
|
|
376
|
-
Description: Use the stock decorators (`@log`, `@debug`, `@info`, `@verbose`, `@silly`, `@benchmark`, `@final`) or extend `@log` to emit structured entry/exit details. Decorators work with `LoggedClass` instances and plain classes alike.
|
|
377
|
-
|
|
378
|
-
```mermaid
|
|
379
|
-
sequenceDiagram
|
|
380
|
-
autonumber
|
|
381
|
-
participant Caller as Caller
|
|
382
|
-
participant Decorator as @log
|
|
383
|
-
participant Method as Original Method
|
|
384
|
-
participant Logger as Logger Proxy
|
|
385
|
-
Caller->>Decorator: invoke decorated method
|
|
386
|
-
Decorator->>Logger: log(entryMessage(args))
|
|
387
|
-
Decorator->>Method: Reflect.apply(...)
|
|
388
|
-
Method-->>Decorator: result / Promise
|
|
389
|
-
Decorator->>Logger: log(exitMessage or benchmark)
|
|
390
|
-
```
|
|
260
|
+
```typescript
|
|
261
|
+
import { log, LogLevel } from '@decaf-ts/logging';
|
|
391
262
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
info,
|
|
397
|
-
silly,
|
|
398
|
-
verbose,
|
|
399
|
-
benchmark,
|
|
400
|
-
LogLevel,
|
|
401
|
-
LoggedClass,
|
|
402
|
-
} from "@decaf-ts/logging";
|
|
403
|
-
|
|
404
|
-
class CustomLogDecorator {
|
|
405
|
-
static payload(label: string) {
|
|
406
|
-
return log(
|
|
407
|
-
LogLevel.info,
|
|
408
|
-
0,
|
|
409
|
-
(...args) => `${label}: ${JSON.stringify(args)}`,
|
|
410
|
-
(err, result) =>
|
|
411
|
-
err ? `${label} failed: ${err.message}` : `${label} ok: ${result}`
|
|
412
|
-
);
|
|
263
|
+
class MyDecoratedService {
|
|
264
|
+
@log(LogLevel.info)
|
|
265
|
+
myMethod(arg1: string) {
|
|
266
|
+
// ...
|
|
413
267
|
}
|
|
414
268
|
}
|
|
269
|
+
```
|
|
415
270
|
|
|
416
|
-
|
|
417
|
-
@CustomLogDecorator.payload("charge")
|
|
418
|
-
@benchmark()
|
|
419
|
-
async charge(userId: string, amount: number) {
|
|
420
|
-
if (amount <= 0) throw new Error("invalid amount");
|
|
421
|
-
return `charged:${userId}:${amount}`;
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
@debug()
|
|
425
|
-
rebuildIndex() {}
|
|
426
|
-
|
|
427
|
-
@info()
|
|
428
|
-
activate() {}
|
|
271
|
+
### `@benchmark`
|
|
429
272
|
|
|
430
|
-
|
|
431
|
-
|
|
273
|
+
```typescript
|
|
274
|
+
import { benchmark } from '@decaf-ts/logging';
|
|
432
275
|
|
|
433
|
-
|
|
434
|
-
|
|
276
|
+
class MyBenchmarkedService {
|
|
277
|
+
@benchmark()
|
|
278
|
+
myLongRunningMethod() {
|
|
279
|
+
// ...
|
|
280
|
+
}
|
|
435
281
|
}
|
|
436
|
-
|
|
437
|
-
const svc = new BillingService();
|
|
438
|
-
await svc.charge("u-1", 25);
|
|
439
|
-
```
|
|
440
|
-
|
|
441
|
-
## 10. Utility Modules (text, time, utils, web)
|
|
442
|
-
Description: Helper functions complement logging by formatting identifiers, generating ENV keys, and detecting runtimes.
|
|
443
|
-
|
|
444
|
-
```ts
|
|
445
|
-
import {
|
|
446
|
-
padEnd,
|
|
447
|
-
patchPlaceholders,
|
|
448
|
-
sf,
|
|
449
|
-
toCamelCase,
|
|
450
|
-
toENVFormat,
|
|
451
|
-
toSnakeCase,
|
|
452
|
-
toKebabCase,
|
|
453
|
-
toPascalCase,
|
|
454
|
-
} from "@decaf-ts/logging/text";
|
|
455
|
-
import { formatMs, now } from "@decaf-ts/logging/time";
|
|
456
|
-
import { getObjectName, isClass, isFunction, isInstance } from "@decaf-ts/logging/utils";
|
|
457
|
-
import { isBrowser } from "@decaf-ts/logging/web";
|
|
458
|
-
|
|
459
|
-
const padded = padEnd("id", 5, "_"); // "id___"
|
|
460
|
-
const greeting = patchPlaceholders("Hello ${name}", { name: "Ada" });
|
|
461
|
-
const formatted = sf("{0}-{name}", "A", { name: "B" });
|
|
462
|
-
const snake = toSnakeCase("HelloWorld Test"); // "hello_world_test"
|
|
463
|
-
const envKey = toENVFormat("service.host"); // "SERVICE_HOST"
|
|
464
|
-
const camel = toCamelCase("hello world");
|
|
465
|
-
const pascal = toPascalCase("hello world");
|
|
466
|
-
const kebab = toKebabCase("Hello World");
|
|
467
|
-
|
|
468
|
-
const duration = formatMs(now() - now()); // hh:mm:ss.mmm string
|
|
469
|
-
const typeName = getObjectName(new (class Repo {})());
|
|
470
|
-
const runtimeIsBrowser = isBrowser();
|
|
471
|
-
const plainFn = () => true;
|
|
472
|
-
console.log(isFunction(plainFn), isClass(class A {}), isInstance({})); // type guards
|
|
473
282
|
```
|
|
474
283
|
|
|
475
284
|
|
package/dist/logging.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var t,e;t=this,e=function(t,e,r,o){"use strict";const n="ENV",s="__",i=["${","}"];var a;t.LogLevel=void 0,(a=t.LogLevel||(t.LogLevel={})).benchmark="benchmark",a.error="error",a.warn="warn",a.info="info",a.verbose="verbose",a.debug="debug",a.trace="trace",a.silly="silly";const c={benchmark:0,error:3,warn:6,info:9,verbose:12,debug:15,trace:18,silly:21};var l;t.LoggingMode=void 0,(l=t.LoggingMode||(t.LoggingMode={})).RAW="raw",l.JSON="json";const g={app:{},separator:{},class:{fg:34},id:{fg:36},stack:{},timestamp:{},message:{error:{fg:31}},method:{},logLevel:{benchmark:{fg:32,style:["bold"]},error:{fg:31,style:["bold"]},info:{fg:34,style:["bold"]},verbose:{fg:34,style:["bold"]},debug:{fg:33,style:["bold"]},trace:{fg:33,style:["bold"]},silly:{fg:33,style:["bold"]}}},u={env:"development",verbose:0,level:t.LogLevel.info,logLevel:!0,style:!1,contextSeparator:".",separator:"-",timestamp:!0,timestampFormat:"HH:mm:ss.SSS",context:!0,meta:!0,format:t.LoggingMode.RAW,pattern:"{level} [{timestamp}] {app} {context} {separator} {message} {stack}",theme:g};function f(t,e,r="g"){return Object.entries(e).forEach(([e,o])=>{const n=RegExp(y(e),r);t=t.replace(n,o)}),t}function h(t){return p(t).toUpperCase()}function p(t){return t.replace(/([a-z])([A-Z])/g,"$1_$2").replace(/[\s-]+/g,"_").toLowerCase()}function y(t){return t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function b(t,...e){if(e.length>1&&!e.every(t=>"string"==typeof t||"number"==typeof t))throw Error("Only string and number arguments are supported for multiple replacements.");if(1===e.length&&"object"==typeof e[0]){const r=e[0];return Object.entries(r).reduce((t,[e,r])=>t.replace(RegExp(`\\{${e}\\}`,"g"),()=>r),t)}return t.replace(/{(\d+)}/g,(t,r)=>void 0!==e[r]?e[r].toString():"undefined")}const d=b;function m(){return Object.getPrototypeOf(Object.getPrototypeOf(globalThis))!==Object.prototype}const v=Symbol("EnvironmentEmpty"),w=Symbol("EnvironmentModel");class L extends r.ObjectAccumulator{static{this.factory=()=>new L}constructor(){super(),Object.defineProperty(this,w,{value:{},writable:!0,enumerable:!1,configurable:!1})}fromEnv(t){let e;return m()?e=globalThis[n]||{}:(e=globalThis.process.env,t=h(t)),this.parseEnvValue(e[t])}parseEnvValue(t){if("string"!=typeof t)return t;if("true"===t)return!0;if("false"===t)return!1;const e=parseFloat(t);return isNaN(e)?t:e}expand(t){Object.entries(t).forEach(([t,e])=>{L.mergeModel(this[w],t,e),Object.defineProperty(this,t,{get:()=>{const r=this.fromEnv(t);return void 0!==r?r:e&&"object"==typeof e?L.buildEnvProxy(e,[t]):""===e?v:e},set:t=>{e=t},configurable:!0,enumerable:!0})})}orThrow(){const t=this[w],e=t=>t.map(t=>h(t)).join(s),r=t=>L.readRuntimeEnv(t),o=t=>void 0!==t?this.parseEnvValue(t):void 0,n=(t,e=!1)=>L.missingEnvError(t,e),i=(t,s)=>new Proxy({},{get(a,c){if("string"!=typeof c)return;const l=[...s,c],g=e(l),u=r(g);if("string"==typeof u&&0===u.length)throw n(g,!0);const f=o(u);if(void 0!==f){if("string"==typeof f&&0===f.length)throw n(g,!0);return f}if(!t||!Object.prototype.hasOwnProperty.call(t,c))throw n(g);const h=t[c];if(void 0!==h){if(""===h)throw n(g);return h&&"object"==typeof h&&!Array.isArray(h)?i(h,l):h}},ownKeys:()=>t?Reflect.ownKeys(t):[],getOwnPropertyDescriptor(e,r){if(t)return Object.prototype.hasOwnProperty.call(t,r)?{enumerable:!0,configurable:!0}:void 0}});return new Proxy(this,{get(s,a,c){if("string"!=typeof a)return Reflect.get(s,a,c);if(!Object.prototype.hasOwnProperty.call(t,a))return Reflect.get(s,a,c);const l=e([a]),g=r(l);if("string"==typeof g&&0===g.length)throw n(l,!0);const u=o(g);if(void 0!==u){if("string"==typeof u&&0===u.length)throw n(l,!0);return u}const f=t[a];if(f&&"object"==typeof f&&!Array.isArray(f))return i(f,[a]);if(void 0===f)return Reflect.get(s,a,c);const h=Reflect.get(s,a);if(void 0===h||""===h)throw n(l,""===h);return h}})}static instance(...t){if(!L._instance){const e=L.factory(...t),r=new Proxy(e,{get(t,e,r){const o=Reflect.get(t,e,r);if(o!==v&&("string"!=typeof e||!Object.prototype.hasOwnProperty.call(t,e)||void 0!==o)){if(void 0!==o)return o;if("string"==typeof e){if("app"===e)return;return L.buildEnvProxy(void 0,[e])}return o}}});L._instance=r}return L._instance}accumulate(t){return super.accumulate(t),this}static accumulate(t){const e=L.instance();return Object.keys(e).forEach(t=>{const r=Object.getOwnPropertyDescriptor(e,t);r&&r.configurable&&r.enumerable&&Object.defineProperty(e,t,{...r,enumerable:!1})}),e.accumulate(t),e}static get(t){return L._instance.get(t)}static buildEnvProxy(t,e){const r=t=>t.map(t=>h(t)).join(s);return new Proxy({},{get(o,n){if(n===Symbol.toPrimitive)return()=>r(e);if("toString"===n)return()=>r(e);if("valueOf"===n)return()=>r(e);if("symbol"==typeof n)return;const s=!!t&&Object.prototype.hasOwnProperty.call(t,n),i=s?t[n]:void 0,a=[...e,n],c=(l=r(a),L.readRuntimeEnv(l));var l;return void 0!==c?c:i&&"object"==typeof i?L.buildEnvProxy(i,a):s&&""===i||s&&void 0===i?void 0:L.buildEnvProxy(void 0,a)},ownKeys:()=>t?Reflect.ownKeys(t):[],getOwnPropertyDescriptor(e,r){if(t)return Object.prototype.hasOwnProperty.call(t,r)?{enumerable:!0,configurable:!0}:void 0}})}static keys(t=!0){return L.instance().keys().map(e=>t?h(e):e)}static mergeModel(t,e,r){if(t){if(r&&"object"==typeof r&&!Array.isArray(r)){const o=t[e],n=o&&"object"==typeof o&&!Array.isArray(o)?o:{};return t[e]=n,void Object.entries(r).forEach(([t,e])=>{L.mergeModel(n,t,e)})}t[e]=r}}static readRuntimeEnv(t){if(m()){const e=globalThis[n];return e?e[t]:void 0}return globalThis?.process?.env?.[t]}static missingEnvError(t,e){return Error(`Environment variable ${t} is required but was ${e?"an empty string":"undefined"}.`)}}const x=L.accumulate(Object.assign({app:void 0},u,{env:(m()&&globalThis[n]?globalThis[n].NODE_ENV:globalThis.process.env.NODE_ENV)||"development"}));function _(t){if("function"!=typeof t)return!1;try{const e=Function.prototype.toString.call(t);if(/^\s*class[\s{]/.test(e))return!0}catch{}const e=Object.getOwnPropertyDescriptor(t,"prototype");if(!e||!e.value)return!1;if(!1===e.writable)return!0;const r=t.prototype;return!!Object.prototype.hasOwnProperty.call(r,"constructor")&&Object.getOwnPropertyNames(r).filter(t=>"constructor"!==t).length>0}function O(t){return"function"==typeof t&&!_(t)}function E(t){if(!O(t))return!1;const e=Object.getOwnPropertyDescriptor(t,"prototype");return!e||void 0===e.value}function j(t){if(null===t||"object"!=typeof t)return!1;const e=t.constructor;return!(!e||e===Object)&&_(e)}function M(t){if(null===t)return"null";if(void 0===t)return"undefined";if("string"==typeof t)return t;if(_(t))return t.name||"AnonymousClass";if(j(t)){const e=t.toString;if("function"==typeof e&&e!==Object.prototype.toString)try{const r=e.call(t);if("string"==typeof r&&r.length)return r}catch{}const r=t.constructor;return r&&r.name?r.name:"AnonymousInstance"}if(E(t)||O(t)){const e=t;return e.name?e.name:"anonymous"}if("object"==typeof t){const e=Object.prototype.toString.call(t),r=/^\[object ([^\]]+)\]$/.exec(e);return r?.[1]?r[1]:"Object"}return typeof t}const A=Symbol("MiniLoggerRootContext");class P{constructor(t,e,r=[]){this.conf=e,this.baseContext=Array.isArray(r)?[...r]:[],t&&this.baseContext.push(t),this.context=[...this.baseContext],this[A]=[...this.baseContext]}config(t){return this.conf&&t in this.conf?this.conf[t]:C.getConfig()[t]}for(t,e,...r){let o,n=e;const s=Array.isArray(this.context)?[...this.context]:"string"==typeof this.context&&this.context?[this.context]:[],i=this[A],a=Array.isArray(i)?[...i]:Array.isArray(this.baseContext)?[...this.baseContext]:[];"string"==typeof t?o=t:void 0!==t&&(_(t)||j(t)||O(t)?o=M(t):!n&&t&&"object"==typeof t&&(n=t));let c=o?[...s,o]:[...s];return new Proxy(this,{get:(t,e,r)=>{const o=Reflect.get(t,e,r);return"config"===e?new Proxy(this.config,{apply:(t,e,o)=>{const[s]=o;return n&&void 0!==s&&s in n?n[s]:Reflect.apply(t,r,o)},get:(t,e)=>n&&e in n?n[e]:Reflect.get(t,e,r)}):"clear"===e?()=>(c=[...a],n=void 0,r):"context"===e?c:"root"===e?[...a]:e===A?a:"for"===e?(...e)=>{const r=Array.isArray(t.context)?[...t.context]:"string"==typeof t.context&&t.context?[t.context]:[];t.context=[...c];try{return t.for.apply(t,e)}finally{t.context=r}}:o}})}createLog(t,e,r,o){const n={},s=this.config("style"),i=this.config("separator"),a=C.getConfig().app;if(a&&(n.app=s?C.theme(a,"app",t):a),i&&(n.separator=s?C.theme(i,"separator",t):i),this.config("timestamp")){const e=(new Date).toISOString(),r=s?C.theme(e,"timestamp",t):e;n.timestamp=r}if(this.config("logLevel")){const e=s?C.theme(t,"logLevel",t):t;n.level=e.toUpperCase()}if(this.config("context")){const e=Array.isArray(this.context)?this.context:"string"==typeof this.context&&this.context?[this.context]:[];if(e.length){const r=e.join(this.config("contextSeparator")||"."),o=s?C.theme(r,"class",t):r;n.context=o}}if(this.config("correlationId")){const e=s?C.theme(this.config("correlationId").toString(),"id",t):this.config("correlationId").toString();n.correlationId=e}const c=s?C.theme("string"==typeof e?e:e.message,"message",t):"string"==typeof e?e:e.message;n.message=c;const l=this.config("meta")&&o?o:void 0,g=l?this.formatMeta(l):void 0;if(l&&(n.meta=l),r||e instanceof Error){const o=s?C.theme(r?.stack||e.stack,"stack",t):r?.stack||"";n.stack=` | ${(r||e).message} - Stack trace:\n${o}`}switch(this.config("format")){case"json":return JSON.stringify(n);case"raw":{const t=this.config("pattern").split(" ").map(t=>{if(!t.match(/\{.*?}/g))return t;const e=b(t,n);return e!==t?e:void 0}).filter(t=>t).join(" ");return g?`${t} ${g}`:t}default:throw Error("Unsupported logging format: "+this.config("format"))}}formatMeta(t){try{return JSON.stringify(t)}catch(e){return t+""}}log(e,r,o,n){const s=this.config("level");if(c[e]>c[s])return;let i;switch(e){case t.LogLevel.benchmark:case t.LogLevel.info:case t.LogLevel.verbose:i=console.log;break;case t.LogLevel.debug:i=console.debug;break;case t.LogLevel.error:i=console.error;break;case t.LogLevel.trace:i=console.trace;break;case t.LogLevel.warn:i=console.warn;break;case t.LogLevel.silly:i=console.debug;break;default:throw Error("Invalid log level")}i(this.createLog(e,r,o,n))}benchmark(e,r){this.log(t.LogLevel.benchmark,e,void 0,r)}silly(e,r=0,o){const n="number"==typeof r?r:0,s="number"==typeof r?o:r;this.config("verbose")<n||this.log(t.LogLevel.silly,e,void 0,s)}verbose(e,r=0,o){const n="number"==typeof r?r:0,s="number"==typeof r?o:r;this.config("verbose")<n||this.log(t.LogLevel.verbose,e,void 0,s)}info(e,r){this.log(t.LogLevel.info,e,void 0,r)}debug(e,r){this.log(t.LogLevel.debug,e,void 0,r)}error(e,r,o){let n,s;r instanceof Error?(n=r,s=o):s=r,this.log(t.LogLevel.error,e,n,s)}warn(e,r){this.log(t.LogLevel.warn,e,void 0,r)}trace(e,r){this.log(t.LogLevel.trace,e,void 0,r)}setConfig(t){this.conf={...this.conf||{},...t}}get root(){return[...this.baseContext]}clear(){return this.context=[...this.baseContext],this}}class C{static{this._factory=(t,e)=>{const r="string"==typeof x.app?[x.app]:[];return new P(t,e,r)}}static{this._config=x}constructor(){}static setFactory(t){C._factory=t,this.global=void 0}static setConfig(t){Object.entries(t).forEach(([t,e])=>{this._config[t]=e})}static getConfig(){return this._config}static get(){return this.ensureRoot()}static verbose(t,e=0,r){return this.get().verbose(t,e,r)}static info(t,e){return this.get().info(t,e)}static trace(t,e){return this.get().trace(t,e)}static debug(t,e){return this.get().debug(t,e)}static benchmark(t,e){return this.get().benchmark(t,e)}static silly(t,e=0,r){return this.get().silly(t,e,r)}static warn(t,e){return this.get().warn(t,e)}static error(t,e,r){return this.get().error(t,e,r)}static for(t,e,...r){const o=void 0!==e?[t,e]:[t];return(this.global?this.global:this.ensureRoot(r)).for(...o)}static because(t,e){let r=this.ensureRoot().for(t,this._config);return e&&(r=r.for(e)),r}static baseContext(){const t=this._config.app;return"string"==typeof t&&t.length?[t]:[]}static attachRootContext(t){const e=t.root&&Array.isArray(t.root)?[...t.root]:this.baseContext();return(!t.context||Array.isArray(t.context)&&0===t.context.length)&&(t.context=[...e]),t[A]=[...e],t}static ensureRoot(t=[]){if(!this.global){const e=this._factory(void 0,void 0,...t);this.global=this.attachRootContext(e)}return this.global}static theme(r,o,n,s=g){if(!this._config.style)return r;const i=s[o];if(!i||!Object.keys(i).length)return r;let a=i;const c=Object.assign({},t.LogLevel);return Object.keys(i)[0]in c&&(a=i[n]||{}),Object.keys(a).reduce((t,r)=>{const o=a[r];return o?((t,r,o)=>{try{const n=t;let s=e.style(n);function i(t,r=!1){let i=r?s.background:s.foreground;if(!Array.isArray(t))return i.call(s,o);switch(t.length){case 1:return i=r?s.bgColor256:s.color256,i(t[0]);case 3:return i=r?s.bgRgb:s.rgb,s.rgb(t[0],t[1],t[2]);default:return e.style(n)}}function a(t){s="number"==typeof t?s.style(t):s[t]}switch(r){case"bg":case"fg":return i(o).text;case"style":return Array.isArray(o)?o.forEach(a):a(o),s.text;default:return n}}catch(c){return t}})(t,r,o):t},r)}}class k{get log(){return this._log||(this._log=C.for(this)),this._log}constructor(){}}class S extends k{get log(){return super.log.for(this,{filters:[]})}}const R="undefined"!=typeof globalThis&&"function"==typeof globalThis.performance?.now?()=>globalThis.performance.now():"undefined"!=typeof process&&"function"==typeof process.hrtime?.bigint?()=>{const t=process.hrtime.bigint();return Number(t)/1e6}:()=>Date.now();function $(t){const e=0>t?"-":"",r=Math.abs(t),o=Math.floor(r/36e5),n=Math.floor(r%36e5/6e4),s=Math.floor(r%6e4/1e3),i=Math.floor(r%1e3),a=(t,e)=>t.toString().padStart(e,"0");return`${e}${a(o,2)}:${a(n,2)}:${a(s,2)}.${a(i,3)}`}function T(e=t.LogLevel.info,r=0,o=(...t)=>"called with "+t,n){return(t,s,i)=>{if(!i||"number"==typeof i)throw Error("Logging decoration only applies to methods");const a=t instanceof k?t.log.for(t[s]):C.for(t).for(t[s]),c=a[e].bind(a),l=i.value;return i.value=new Proxy(l,{apply(t,e,s){c(o(...s),r);try{const r=Reflect.apply(t,e,s);return r instanceof Promise?r.then(t=>(n&&c(n(void 0,t)),t)).catch(t=>{throw n&&a.error(n(t)),t}):(n&&c(n(void 0,r)),r)}catch(t){throw n&&a.error(n(t)),t}}}),i}}function N(){return(t,e,r)=>{if(!r)throw Error("final decorator can only be used on methods");return r?.configurable&&(r.configurable=!1),r}}class I extends S{constructor(t,e){super(),this.regexp=t,this.replacement=e}match(t){const e=this.regexp.exec(t);return this.regexp.lastIndex=0,e}filter(t,e,r){const o=this.log.for(this.filter);if(!this.match(e))return e;try{return e.replace(this.regexp,this.replacement)}catch(t){o.error("PatternFilter replacement error: "+t)}return""}}o.__decorate([N(),o.__metadata("design:type",Function),o.__metadata("design:paramtypes",[String]),o.__metadata("design:returntype",void 0)],I.prototype,"match",null),t.BrowserEnvKey=n,t.DefaultLoggingConfig=u,t.DefaultPlaceholderWrappers=i,t.DefaultTheme=g,t.ENV_PATH_DELIMITER=s,t.Environment=L,t.LogFilter=S,t.LoggedClass=k,t.LoggedEnvironment=x,t.Logging=C,t.MiniLogger=P,t.NumericLogLevels=c,t.PACKAGE_NAME="##PACKAGE##",t.PatternFilter=I,t.ROOT_CONTEXT_SYMBOL=A,t.StopWatch=class{constructor(t=!1){this._startMs=null,this._elapsedMs=0,this._running=!1,this._laps=[],this._lastLapTotalMs=0,t&&this.start()}get running(){return this._running}get elapsedMs(){return this._running&&null!=this._startMs?this._elapsedMs+(R()-this._startMs):this._elapsedMs}start(){return this._running||(this._running=!0,this._startMs=R()),this}pause(){return this._running&&null!=this._startMs&&(this._elapsedMs+=R()-this._startMs,this._startMs=null,this._running=!1),this}resume(){return this._running||(this._running=!0,this._startMs=R()),this}stop(){return this.pause(),this._elapsedMs}reset(){const t=this._running;return this._startMs=t?R():null,this._elapsedMs=0,this._laps=[],this._lastLapTotalMs=0,this}lap(t){const e=this.elapsedMs,r=e-this._lastLapTotalMs,o={index:this._laps.length,label:t,ms:r,totalMs:e};return this._laps.push(o),this._lastLapTotalMs=e,o}get laps(){return this._laps}toString(){return $(this.elapsedMs)}toJSON(){return{running:this._running,elapsedMs:this.elapsedMs,laps:this._laps.slice()}}},t.VERSION="##VERSION##",t.benchmark=()=>(t,e,r)=>{if(!r||"number"==typeof r)throw Error("benchmark decoration only applies to methods");const o=t instanceof k?t.log.for(t[e]):C.for(t).for(t[e]),n=r.value;return r.value=new Proxy(n,{apply(t,e,r){const n=R();try{const s=Reflect.apply(t,e,r);return s instanceof Promise?s.then(t=>(o.benchmark(`completed in ${R()-n}ms`),t)).catch(t=>{throw o.benchmark(`failed in ${R()-n}ms`),t}):(o.benchmark(`completed in ${R()-n}ms`),s)}catch(t){throw o.benchmark(`failed in ${R()-n}ms`),t}}}),r},t.debug=()=>T(t.LogLevel.debug,0,(...t)=>"called with "+t,(t,e)=>t?"Failed with: "+t:e?"Completed with "+JSON.stringify(e):"completed"),t.escapeRegExp=y,t.final=N,t.formatMs=$,t.getObjectName=M,t.info=()=>T(t.LogLevel.info),t.isBrowser=m,t.isClass=_,t.isFunction=O,t.isInstance=j,t.isMethod=E,t.log=T,t.now=R,t.padEnd=(t,e,r=" ")=>{if(1!==r.length)throw Error("Invalid character length for padding. must be one!");return t.padEnd(e,r)},t.patchPlaceholders=(t,e,r=i[0],o=i[1],n="g")=>f(t,Object.entries(e).reduce((t,[e,n])=>(t[`${r}${e}${o}`]=n,t),{}),n),t.patchString=f,t.sf=b,t.silly=()=>T(t.LogLevel.silly),t.stringFormat=d,t.toCamelCase=t=>t.replace(/(?:^\w|[A-Z]|\b\w)/g,(t,e)=>0===e?t.toLowerCase():t.toUpperCase()).replace(/\s+/g,""),t.toENVFormat=h,t.toKebabCase=t=>t.replace(/([a-z])([A-Z])/g,"$1-$2").replace(/[\s_]+/g,"-").toLowerCase(),t.toPascalCase=t=>t.replace(/(?:^\w|[A-Z]|\b\w)/g,t=>t.toUpperCase()).replace(/\s+/g,""),t.toSnakeCase=p,t.trace=()=>T(t.LogLevel.trace),t.verbose=(e=0)=>(e||(e=0),T(t.LogLevel.verbose,e)),Object.keys(e).forEach(r=>{"default"===r||t.hasOwnProperty(r)||Object.defineProperty(t,r,{enumerable:!0,get:()=>e[r]})})},"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("styled-string-builder"),require("typed-object-accumulator"),require("tslib")):"function"==typeof define&&define.amd?define(["exports","styled-string-builder","typed-object-accumulator","tslib"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).logging={},t.styledStringBuilder,t.typedObjectAccumulator,t.tslib);
|
|
1
|
+
var t,e;t=this,e=function(t,e,r,o){"use strict";const n="ENV",s="__",i=["${","}"];var a;t.LogLevel=void 0,(a=t.LogLevel||(t.LogLevel={})).benchmark="benchmark",a.error="error",a.warn="warn",a.info="info",a.verbose="verbose",a.debug="debug",a.trace="trace",a.silly="silly";const c={benchmark:0,error:3,warn:6,info:9,verbose:12,debug:15,trace:18,silly:21};var l;t.LoggingMode=void 0,(l=t.LoggingMode||(t.LoggingMode={})).RAW="raw",l.JSON="json";const g={app:{},separator:{},class:{fg:34},id:{fg:36},stack:{},timestamp:{},message:{error:{fg:31}},method:{},logLevel:{benchmark:{fg:32,style:["bold"]},error:{fg:31,style:["bold"]},info:{fg:34,style:["bold"]},verbose:{fg:34,style:["bold"]},debug:{fg:33,style:["bold"]},trace:{fg:33,style:["bold"]},silly:{fg:33,style:["bold"]}}},u={env:"development",verbose:0,level:t.LogLevel.info,logLevel:!0,style:!1,contextSeparator:".",separator:"-",timestamp:!0,timestampFormat:"HH:mm:ss.SSS",context:!0,meta:!0,format:t.LoggingMode.RAW,pattern:"{level} [{timestamp}] {app} {context} {separator} {message} {stack}",theme:g};function f(t,e,r="g"){return Object.entries(e).forEach((([e,o])=>{const n=RegExp(y(e),r);t=t.replace(n,o)})),t}function h(t){return p(t).toUpperCase()}function p(t){return t.replace(/([a-z])([A-Z])/g,"$1_$2").replace(/[\s-]+/g,"_").toLowerCase()}function y(t){return t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function b(t,...e){if(e.length>1&&!e.every((t=>"string"==typeof t||"number"==typeof t)))throw Error("Only string and number arguments are supported for multiple replacements.");if(1===e.length&&"object"==typeof e[0]){const r=e[0];return Object.entries(r).reduce(((t,[e,r])=>t.replace(RegExp(`\\{${e}\\}`,"g"),(()=>r))),t)}return t.replace(/{(\d+)}/g,((t,r)=>void 0!==e[r]?e[r].toString():"undefined"))}const d=b;function m(){return Object.getPrototypeOf(Object.getPrototypeOf(globalThis))!==Object.prototype}const v=Symbol("EnvironmentEmpty"),w=Symbol("EnvironmentModel");class L extends r.ObjectAccumulator{static{this.factory=()=>new L}constructor(){super(),Object.defineProperty(this,w,{value:{},writable:!0,enumerable:!1,configurable:!1})}fromEnv(t){let e;return m()?e=globalThis[n]||{}:(e=globalThis.process.env,t=h(t)),this.parseEnvValue(e[t])}parseEnvValue(t){return L.parseRuntimeValue(t)}static parseRuntimeValue(t){if("string"!=typeof t)return t;if("true"===t)return!0;if("false"===t)return!1;const e=parseFloat(t);return Number.isNaN(e)?t:e}expand(t){Object.entries(t).forEach((([t,e])=>{L.mergeModel(this[w],t,e),Object.defineProperty(this,t,{get:()=>{const r=this.fromEnv(t);return void 0!==r?r:e&&"object"==typeof e?L.buildEnvProxy(e,[t]):""===e?v:e},set:t=>{e=t},configurable:!0,enumerable:!0})}))}orThrow(){const t=this[w],e=t=>t.map((t=>h(t))).join(s),r=t=>L.readRuntimeEnv(t),o=t=>void 0!==t?this.parseEnvValue(t):void 0,n=(t,e=!1)=>L.missingEnvError(t,e),i=(t,s)=>new Proxy({},{get(a,c){if("string"!=typeof c)return;const l=[...s,c],g=e(l),u=r(g);if("string"==typeof u&&0===u.length)throw n(g,!0);const f=o(u);if(void 0!==f){if("string"==typeof f&&0===f.length)throw n(g,!0);return f}if(!t||!Object.prototype.hasOwnProperty.call(t,c))throw n(g);const h=t[c];if(void 0!==h){if(""===h)throw n(g);return h&&"object"==typeof h&&!Array.isArray(h)?i(h,l):h}},ownKeys:()=>t?Reflect.ownKeys(t):[],getOwnPropertyDescriptor(e,r){if(t)return Object.prototype.hasOwnProperty.call(t,r)?{enumerable:!0,configurable:!0}:void 0}});return new Proxy(this,{get(s,a,c){if("string"!=typeof a)return Reflect.get(s,a,c);if(!Object.prototype.hasOwnProperty.call(t,a))return Reflect.get(s,a,c);const l=e([a]),g=r(l);if("string"==typeof g&&0===g.length)throw n(l,!0);const u=o(g);if(void 0!==u){if("string"==typeof u&&0===u.length)throw n(l,!0);return u}const f=t[a];if(f&&"object"==typeof f&&!Array.isArray(f))return i(f,[a]);if(void 0===f)return Reflect.get(s,a,c);const h=Reflect.get(s,a);if(void 0===h||""===h)throw n(l,""===h);return h}})}static instance(...t){if(!L._instance){const e=L.factory(...t),r=new Proxy(e,{get(t,e,r){const o=Reflect.get(t,e,r);if(o!==v&&("string"!=typeof e||!Object.prototype.hasOwnProperty.call(t,e)||void 0!==o)){if(void 0!==o)return o;if("string"==typeof e){if("app"===e)return;return L.buildEnvProxy(void 0,[e])}return o}}});L._instance=r}return L._instance}accumulate(t){return super.accumulate(t),this}static accumulate(t){const e=L.instance();return Object.keys(e).forEach((t=>{const r=Object.getOwnPropertyDescriptor(e,t);r&&r.configurable&&r.enumerable&&Object.defineProperty(e,t,{...r,enumerable:!1})})),e.accumulate(t),e}static get(t){return L._instance.get(t)}static buildEnvProxy(t,e){const r=t=>t.map((t=>h(t))).join(s);return new Proxy({},{get(o,n){if(n===Symbol.toPrimitive)return()=>r(e);if("toString"===n)return()=>r(e);if("valueOf"===n)return()=>r(e);if("symbol"==typeof n)return;const s=!!t&&Object.prototype.hasOwnProperty.call(t,n),i=s?t[n]:void 0,a=[...e,n],c=(l=r(a),L.readRuntimeEnv(l));var l;return void 0!==c?L.parseRuntimeValue(c):i&&"object"==typeof i?L.buildEnvProxy(i,a):s&&""===i||s&&void 0===i?void 0:L.buildEnvProxy(void 0,a)},ownKeys:()=>t?Reflect.ownKeys(t):[],getOwnPropertyDescriptor(e,r){if(t)return Object.prototype.hasOwnProperty.call(t,r)?{enumerable:!0,configurable:!0}:void 0}})}static keys(t=!0){return L.instance().keys().map((e=>t?h(e):e))}static mergeModel(t,e,r){if(t){if(r&&"object"==typeof r&&!Array.isArray(r)){const o=t[e],n=o&&"object"==typeof o&&!Array.isArray(o)?o:{};return t[e]=n,void Object.entries(r).forEach((([t,e])=>{L.mergeModel(n,t,e)}))}t[e]=r}}static readRuntimeEnv(t){if(m()){const e=globalThis[n];return e?e[t]:void 0}return globalThis?.process?.env?.[t]}static missingEnvError(t,e){return Error(`Environment variable ${t} is required but was ${e?"an empty string":"undefined"}.`)}}const x=L.accumulate(Object.assign({app:void 0},u,{env:(m()&&globalThis[n]?globalThis[n].NODE_ENV:globalThis.process.env.NODE_ENV)||"development"}));function _(t){if("function"!=typeof t)return!1;try{const e=Function.prototype.toString.call(t);if(/^\s*class[\s{]/.test(e))return!0}catch{}const e=Object.getOwnPropertyDescriptor(t,"prototype");if(!e||!e.value)return!1;if(!1===e.writable)return!0;const r=t.prototype;return!!Object.prototype.hasOwnProperty.call(r,"constructor")&&Object.getOwnPropertyNames(r).filter((t=>"constructor"!==t)).length>0}function O(t){return"function"==typeof t&&!_(t)}function E(t){if(!O(t))return!1;const e=Object.getOwnPropertyDescriptor(t,"prototype");return!e||void 0===e.value}function j(t){if(null===t||"object"!=typeof t)return!1;const e=t.constructor;return!(!e||e===Object)&&_(e)}function M(t){if(null===t)return"null";if(void 0===t)return"undefined";if("string"==typeof t)return t;if(_(t))return t.name||"AnonymousClass";if(j(t)){const e=t.toString;if("function"==typeof e&&e!==Object.prototype.toString)try{const r=e.call(t);if("string"==typeof r&&r.length)return r}catch{}const r=t.constructor;return r&&r.name?r.name:"AnonymousInstance"}if(E(t)||O(t)){const e=t;return e.name?e.name:"anonymous"}if("object"==typeof t){const e=Object.prototype.toString.call(t),r=/^\[object ([^\]]+)\]$/.exec(e);return r?.[1]?r[1]:"Object"}return typeof t}const A=Symbol("MiniLoggerRootContext");class P{constructor(t,e,r=[]){this.conf=e,this.baseContext=Array.isArray(r)?[...r]:[],t&&this.baseContext.push(t),this.context=[...this.baseContext],this[A]=[...this.baseContext]}config(t){return this.conf&&t in this.conf?this.conf[t]:C.getConfig()[t]}for(t,e,...r){let o,n=e;const s=Array.isArray(this.context)?[...this.context]:"string"==typeof this.context&&this.context?[this.context]:[],i=this[A],a=Array.isArray(i)?[...i]:Array.isArray(this.baseContext)?[...this.baseContext]:[];"string"==typeof t?o=t:void 0!==t&&(_(t)||j(t)||O(t)?o=M(t):!n&&t&&"object"==typeof t&&(n=t));let c=o?[...s,o]:[...s];return new Proxy(this,{get:(t,e,r)=>{const o=Reflect.get(t,e,r);return"config"===e?new Proxy(this.config,{apply:(t,e,o)=>{const[s]=o;return n&&void 0!==s&&s in n?n[s]:Reflect.apply(t,r,o)},get:(t,e)=>n&&e in n?n[e]:Reflect.get(t,e,r)}):"clear"===e?()=>(c=[...a],n=void 0,r):"context"===e?c:"root"===e?[...a]:e===A?a:"for"===e?(...e)=>{const r=Array.isArray(t.context)?[...t.context]:"string"==typeof t.context&&t.context?[t.context]:[];t.context=[...c];try{return t.for.apply(t,e)}finally{t.context=r}}:o}})}createLog(t,e,r,o){const n={},s=this.config("style"),i=this.config("separator"),a=C.getConfig().app;if(a&&(n.app=s?C.theme(a,"app",t):a),i&&(n.separator=s?C.theme(i,"separator",t):i),this.config("timestamp")){const e=(new Date).toISOString(),r=s?C.theme(e,"timestamp",t):e;n.timestamp=r}if(this.config("logLevel")){const e=s?C.theme(t,"logLevel",t):t;n.level=e.toUpperCase()}if(this.config("context")){const e=Array.isArray(this.context)?this.context:"string"==typeof this.context&&this.context?[this.context]:[];if(e.length){const r=e.join(this.config("contextSeparator")||"."),o=s?C.theme(r,"class",t):r;n.context=o}}if(this.config("correlationId")){const e=s?C.theme(this.config("correlationId").toString(),"id",t):this.config("correlationId").toString();n.correlationId=e}const c=s?C.theme("string"==typeof e?e:e.message,"message",t):"string"==typeof e?e:e.message;n.message=c;const l=this.config("meta")&&o?o:void 0,g=l?this.formatMeta(l):void 0;if(l&&(n.meta=l),r||e instanceof Error){const o=s?C.theme(r?.stack||e.stack,"stack",t):r?.stack||"";n.stack=` | ${(r||e).message} - Stack trace:\n${o}`}switch(this.config("format")){case"json":return JSON.stringify(n);case"raw":{const t=this.config("pattern").split(" ").map((t=>{if(!t.match(/\{.*?}/g))return t;const e=b(t,n);return e!==t?e:void 0})).filter((t=>t)).join(" ");return g?`${t} ${g}`:t}default:throw Error("Unsupported logging format: "+this.config("format"))}}formatMeta(t){try{return JSON.stringify(t)}catch(e){return t+""}}log(e,r,o,n){const s=this.config("level");if(c[e]>c[s])return;let i;switch(e){case t.LogLevel.benchmark:case t.LogLevel.info:case t.LogLevel.verbose:i=console.log;break;case t.LogLevel.debug:i=console.debug;break;case t.LogLevel.error:i=console.error;break;case t.LogLevel.trace:i=console.trace;break;case t.LogLevel.warn:i=console.warn;break;case t.LogLevel.silly:i=console.debug;break;default:throw Error("Invalid log level")}i(this.createLog(e,r,o,n))}benchmark(e,r){this.log(t.LogLevel.benchmark,e,void 0,r)}silly(e,r=0,o){const n="number"==typeof r?r:0,s="number"==typeof r?o:r;this.config("verbose")<n||this.log(t.LogLevel.silly,e,void 0,s)}verbose(e,r=0,o){const n="number"==typeof r?r:0,s="number"==typeof r?o:r;this.config("verbose")<n||this.log(t.LogLevel.verbose,e,void 0,s)}info(e,r){this.log(t.LogLevel.info,e,void 0,r)}debug(e,r){this.log(t.LogLevel.debug,e,void 0,r)}error(e,r,o){let n,s;r instanceof Error?(n=r,s=o):s=r,this.log(t.LogLevel.error,e,n,s)}warn(e,r){this.log(t.LogLevel.warn,e,void 0,r)}trace(e,r){this.log(t.LogLevel.trace,e,void 0,r)}setConfig(t){this.conf={...this.conf||{},...t}}get root(){return[...this.baseContext]}clear(){return this.context=[...this.baseContext],this}}class C{static{this._factory=(t,e)=>{const r="string"==typeof x.app?[x.app]:[];return new P(t,e,r)}}static{this._config=x}constructor(){}static setFactory(t){C._factory=t,this.global=void 0}static setConfig(t){Object.entries(t).forEach((([t,e])=>{this._config[t]=e}))}static getConfig(){return this._config}static get(){return this.ensureRoot()}static verbose(t,e=0,r){return this.get().verbose(t,e,r)}static info(t,e){return this.get().info(t,e)}static trace(t,e){return this.get().trace(t,e)}static debug(t,e){return this.get().debug(t,e)}static benchmark(t,e){return this.get().benchmark(t,e)}static silly(t,e=0,r){return this.get().silly(t,e,r)}static warn(t,e){return this.get().warn(t,e)}static error(t,e,r){return this.get().error(t,e,r)}static for(t,e,...r){const o=void 0!==e?[t,e]:[t];return(this.global?this.global:this.ensureRoot(r)).for(...o)}static because(t,e){let r=this.ensureRoot().for(t,this._config);return e&&(r=r.for(e)),r}static baseContext(){const t=this._config.app;return"string"==typeof t&&t.length?[t]:[]}static attachRootContext(t){const e=t.root&&Array.isArray(t.root)?[...t.root]:this.baseContext();return(!t.context||Array.isArray(t.context)&&0===t.context.length)&&(t.context=[...e]),t[A]=[...e],t}static ensureRoot(t=[]){if(!this.global){const e=this._factory(void 0,void 0,...t);this.global=this.attachRootContext(e)}return this.global}static theme(r,o,n,s=g){if(!this._config.style)return r;const i=s[o];if(!i||!Object.keys(i).length)return r;let a=i;const c=Object.assign({},t.LogLevel);return Object.keys(i)[0]in c&&(a=i[n]||{}),Object.keys(a).reduce(((t,r)=>{const o=a[r];return o?((t,r,o)=>{try{const n=t;let s=e.style(n);function i(t,r=!1){let i=r?s.background:s.foreground;if(!Array.isArray(t))return i.call(s,o);switch(t.length){case 1:return i=r?s.bgColor256:s.color256,i(t[0]);case 3:return i=r?s.bgRgb:s.rgb,s.rgb(t[0],t[1],t[2]);default:return e.style(n)}}function a(t){s="number"==typeof t?s.style(t):s[t]}switch(r){case"bg":case"fg":return i(o).text;case"style":return Array.isArray(o)?o.forEach(a):a(o),s.text;default:return n}}catch(c){return t}})(t,r,o):t}),r)}}class k{get log(){return this._log||(this._log=C.for(this)),this._log}constructor(){}}class S extends k{get log(){return super.log.for(this,{filters:[]})}}const R="undefined"!=typeof globalThis&&"function"==typeof globalThis.performance?.now?()=>globalThis.performance.now():"undefined"!=typeof process&&"function"==typeof process.hrtime?.bigint?()=>{const t=process.hrtime.bigint();return Number(t)/1e6}:()=>Date.now();function $(t){const e=0>t?"-":"",r=Math.abs(t),o=Math.floor(r/36e5),n=Math.floor(r%36e5/6e4),s=Math.floor(r%6e4/1e3),i=Math.floor(r%1e3),a=(t,e)=>t.toString().padStart(e,"0");return`${e}${a(o,2)}:${a(n,2)}:${a(s,2)}.${a(i,3)}`}function T(e=t.LogLevel.info,r=0,o=(...t)=>"called with "+t,n){return(t,s,i)=>{if(!i||"number"==typeof i)throw Error("Logging decoration only applies to methods");const a=t instanceof k?t.log.for(t[s]):C.for(t).for(t[s]),c=a[e].bind(a),l=i.value;return i.value=new Proxy(l,{apply(t,e,s){c(o(...s),r);try{const r=Reflect.apply(t,e,s);return r instanceof Promise?r.then((t=>(n&&c(n(void 0,t)),t))).catch((t=>{throw n&&a.error(n(t)),t})):(n&&c(n(void 0,r)),r)}catch(t){throw n&&a.error(n(t)),t}}}),i}}function N(){return(t,e,r)=>{if(!r)throw Error("final decorator can only be used on methods");return r?.configurable&&(r.configurable=!1),r}}class I extends S{constructor(t,e){super(),this.regexp=t,this.replacement=e}match(t){const e=this.regexp.exec(t);return this.regexp.lastIndex=0,e}filter(t,e,r){const o=this.log.for(this.filter);if(!this.match(e))return e;try{return e.replace(this.regexp,this.replacement)}catch(t){o.error("PatternFilter replacement error: "+t)}return""}}o.__decorate([N(),o.__metadata("design:type",Function),o.__metadata("design:paramtypes",[String]),o.__metadata("design:returntype",void 0)],I.prototype,"match",null),t.BrowserEnvKey=n,t.DefaultLoggingConfig=u,t.DefaultPlaceholderWrappers=i,t.DefaultTheme=g,t.ENV_PATH_DELIMITER=s,t.Environment=L,t.LogFilter=S,t.LoggedClass=k,t.LoggedEnvironment=x,t.Logging=C,t.MiniLogger=P,t.NumericLogLevels=c,t.PACKAGE_NAME="##PACKAGE##",t.PatternFilter=I,t.ROOT_CONTEXT_SYMBOL=A,t.StopWatch=class{constructor(t=!1){this._startMs=null,this._elapsedMs=0,this._running=!1,this._laps=[],this._lastLapTotalMs=0,t&&this.start()}get running(){return this._running}get elapsedMs(){return this._running&&null!=this._startMs?this._elapsedMs+(R()-this._startMs):this._elapsedMs}start(){return this._running||(this._running=!0,this._startMs=R()),this}pause(){return this._running&&null!=this._startMs&&(this._elapsedMs+=R()-this._startMs,this._startMs=null,this._running=!1),this}resume(){return this._running||(this._running=!0,this._startMs=R()),this}stop(){return this.pause(),this._elapsedMs}reset(){const t=this._running;return this._startMs=t?R():null,this._elapsedMs=0,this._laps=[],this._lastLapTotalMs=0,this}lap(t){const e=this.elapsedMs,r=e-this._lastLapTotalMs,o={index:this._laps.length,label:t,ms:r,totalMs:e};return this._laps.push(o),this._lastLapTotalMs=e,o}get laps(){return this._laps}toString(){return $(this.elapsedMs)}toJSON(){return{running:this._running,elapsedMs:this.elapsedMs,laps:this._laps.slice()}}},t.VERSION="##VERSION##",t.benchmark=()=>(t,e,r)=>{if(!r||"number"==typeof r)throw Error("benchmark decoration only applies to methods");const o=t instanceof k?t.log.for(t[e]):C.for(t).for(t[e]),n=r.value;return r.value=new Proxy(n,{apply(t,e,r){const n=R();try{const s=Reflect.apply(t,e,r);return s instanceof Promise?s.then((t=>(o.benchmark(`completed in ${R()-n}ms`),t))).catch((t=>{throw o.benchmark(`failed in ${R()-n}ms`),t})):(o.benchmark(`completed in ${R()-n}ms`),s)}catch(t){throw o.benchmark(`failed in ${R()-n}ms`),t}}}),r},t.debug=()=>T(t.LogLevel.debug,0,((...t)=>"called with "+t),((t,e)=>t?"Failed with: "+t:e?"Completed with "+JSON.stringify(e):"completed")),t.escapeRegExp=y,t.final=N,t.formatMs=$,t.getObjectName=M,t.info=()=>T(t.LogLevel.info),t.isBrowser=m,t.isClass=_,t.isFunction=O,t.isInstance=j,t.isMethod=E,t.log=T,t.now=R,t.padEnd=(t,e,r=" ")=>{if(1!==r.length)throw Error("Invalid character length for padding. must be one!");return t.padEnd(e,r)},t.patchPlaceholders=(t,e,r=i[0],o=i[1],n="g")=>f(t,Object.entries(e).reduce(((t,[e,n])=>(t[`${r}${e}${o}`]=n,t)),{}),n),t.patchString=f,t.sf=b,t.silly=()=>T(t.LogLevel.silly),t.stringFormat=d,t.toCamelCase=t=>t.replace(/(?:^\w|[A-Z]|\b\w)/g,((t,e)=>0===e?t.toLowerCase():t.toUpperCase())).replace(/\s+/g,""),t.toENVFormat=h,t.toKebabCase=t=>t.replace(/([a-z])([A-Z])/g,"$1-$2").replace(/[\s_]+/g,"-").toLowerCase(),t.toPascalCase=t=>t.replace(/(?:^\w|[A-Z]|\b\w)/g,(t=>t.toUpperCase())).replace(/\s+/g,""),t.toSnakeCase=p,t.trace=()=>T(t.LogLevel.trace),t.verbose=(e=0)=>(e||(e=0),T(t.LogLevel.verbose,e)),Object.keys(e).forEach((r=>{"default"===r||t.hasOwnProperty(r)||Object.defineProperty(t,r,{enumerable:!0,get:()=>e[r]})}))},"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("styled-string-builder"),require("typed-object-accumulator"),require("tslib")):"function"==typeof define&&define.amd?define(["exports","styled-string-builder","typed-object-accumulator","tslib"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).logging={},t.styledStringBuilder,t.typedObjectAccumulator,t.tslib);
|
|
2
2
|
//# sourceMappingURL=logging.cjs.map
|