syntropylog 0.12.0 → 0.12.2
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/CHANGELOG.md +14 -0
- package/README.md +78 -14
- package/dist/index.cjs +42 -30
- package/dist/index.d.ts +12 -1
- package/dist/index.mjs +42 -30
- package/dist/testing/index.d.ts +5 -0
- package/dist/types/config/loadLoggerConfig.d.ts +3 -1
- package/dist/types/config.schema.d.ts +2 -0
- package/dist/types/logger/transports/BaseConsolePrettyTransport.d.ts +1 -1
- package/dist/types/logger/transports/Transport.d.ts +5 -0
- package/dist/types/logger/transports/optionalChalk.d.ts +6 -2
- package/dist/types/serialization/SerializationManager.d.ts +2 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.12.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- **Socket / security:** Addressed Socket.dev alerts and clarified behavior in docs. Native addon no longer uses shell (`execSync`): resolves `ldd` path via `PATH` and `fs.existsSync` only. Documented filesystem access (native loader + `loadLoggerConfig`), environment variables (only `PATH` in optional native addon), dynamic require (static paths only), and URL/network (no runtime URLs). SECURITY.md now lists the single env var read (`PATH`) and README Security & Compliance section covers network, env, dynamic require, and filesystem.
|
|
8
|
+
|
|
9
|
+
**Docs - Universal Adapter:** README section 3 reworked: mapping is defined once with `UniversalLogFormatter` (outside the executor); executor receives the mapped object and can send it to multiple backends (e.g. Prisma, TypeORM, Mongoose) in one block. Single example shows one mapping → one object → three destinations with `Promise.all`.
|
|
10
|
+
|
|
3
11
|
## 0.12.0
|
|
4
12
|
|
|
5
13
|
First release after 0.11.3. Includes all framework refinements validated end-to-end with the examples repo (0.11.4 was never published to npm).
|
|
@@ -16,6 +24,12 @@ First release after 0.11.3. Includes all framework refinements validated end-to-
|
|
|
16
24
|
- **Lint:** SerializationManager: replaced `(logEntry as any)` with `Record<string, unknown>`; removed unused destructuring variables in native serialize path (use copy + delete for metadata).
|
|
17
25
|
- **Examples repo:** Full refresh: main set 01–17 only, updated README and test script, self-contained benchmark (17-benchmark), removed obsolete scripts and optional folders.
|
|
18
26
|
|
|
27
|
+
## 0.12.1
|
|
28
|
+
|
|
29
|
+
### Patch Changes
|
|
30
|
+
|
|
31
|
+
- **Security / env:** The package no longer reads any environment variables (addresses tooling such as Socket.dev). Use config/options instead: `logger.disableNativeAddon: true` in `init()` to disable the native addon (replaces `SYNTROPYLOG_NATIVE_DISABLE=1`). For console transports, pass `disableColors: true` or derive from `NO_COLOR` in your app to disable ANSI colors. See SECURITY.md.
|
|
32
|
+
|
|
19
33
|
## 0.11.3
|
|
20
34
|
|
|
21
35
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -160,33 +160,86 @@ await syntropyLog.init({
|
|
|
160
160
|
|
|
161
161
|
## 3. Universal Adapter — log to any backend
|
|
162
162
|
|
|
163
|
-
**What:** Send each log to PostgreSQL, MongoDB, Elasticsearch, S3, etc. by implementing a single `executor`. No vendor lock-in;
|
|
163
|
+
**What:** Send each log to PostgreSQL, MongoDB, Elasticsearch, S3, etc. by implementing a single `executor`. No vendor lock-in. You define **once** how the log entry maps to your schema; the executor only receives that mapped object and persists it (ORM, raw client, HTTP). If `executor` throws, SyntropyLog logs the error and continues (Silent Observer).
|
|
164
164
|
|
|
165
|
-
**How:** Use `AdapterTransport` + `UniversalAdapter
|
|
165
|
+
**How:** Use `AdapterTransport` + `UniversalAdapter` + `UniversalLogFormatter`. Three steps:
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
### 1. Define the mapping (outside the executor)
|
|
170
|
+
|
|
171
|
+
Define how each log entry field maps to your persistence shape. One place, no repetition in code. Use `UniversalLogFormatter` with a `mapping` object: keys = your schema (e.g. DB columns), values = path in the log entry.
|
|
172
|
+
|
|
173
|
+
| Log entry path | Meaning |
|
|
174
|
+
|----------------|--------|
|
|
175
|
+
| `level` | Log level |
|
|
176
|
+
| `message` | Message string |
|
|
177
|
+
| `serviceName` | From init config |
|
|
178
|
+
| `correlationId` | From context |
|
|
179
|
+
| `timestamp` | ISO string |
|
|
180
|
+
| `meta` | Merged metadata (use as payload/JSON column) |
|
|
181
|
+
|
|
182
|
+
Example: map to a table with columns `level`, `message`, `serviceName`, `correlationId`, `payload`, `timestamp`.
|
|
183
|
+
|
|
184
|
+
```typescript
|
|
185
|
+
import { UniversalLogFormatter } from 'syntropylog';
|
|
186
|
+
|
|
187
|
+
const logToDbMapping = {
|
|
188
|
+
level: 'level',
|
|
189
|
+
message: 'message',
|
|
190
|
+
serviceName: 'serviceName',
|
|
191
|
+
correlationId: 'correlationId',
|
|
192
|
+
payload: 'meta',
|
|
193
|
+
timestamp: 'timestamp',
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
const formatter = new UniversalLogFormatter({ mapping: logToDbMapping });
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
The formatter turns every log entry into an object with exactly those keys. Change the mapping here when your schema changes; the executor stays the same.
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
### 2. The object the executor receives
|
|
204
|
+
|
|
205
|
+
When you attach this formatter to the transport, the `executor` receives **that mapped object** (not the raw log entry). So the executor only sees something like `{ level, message, serviceName, correlationId, payload, timestamp }`. Your only job in the executor is to **persist** that object.
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
### 3. Sending that object to your backend
|
|
210
|
+
|
|
211
|
+
One mapping produces one object shape. You can send **that same object** to as many backends as you want in a single executor: same `data`, different destinations (e.g. Prisma, TypeORM, Mongoose, Elasticsearch, S3). No field list — the shape comes from the mapping.
|
|
212
|
+
|
|
213
|
+
**Example: one mapped object → three destinations**
|
|
166
214
|
|
|
167
215
|
```typescript
|
|
168
216
|
import { AdapterTransport, UniversalAdapter } from 'syntropylog';
|
|
217
|
+
import { prisma } from './prisma';
|
|
218
|
+
import { getRepository } from 'typeorm';
|
|
219
|
+
import { SystemLog as TypeOrmSystemLog } from './entities/SystemLog';
|
|
220
|
+
import { SystemLogModel } from './models/SystemLog';
|
|
169
221
|
|
|
170
222
|
const dbTransport = new AdapterTransport({
|
|
171
223
|
name: 'db',
|
|
224
|
+
formatter,
|
|
172
225
|
adapter: new UniversalAdapter({
|
|
173
|
-
executor: async (
|
|
174
|
-
|
|
175
|
-
data
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
226
|
+
executor: async (data) => {
|
|
227
|
+
const row = {
|
|
228
|
+
...data,
|
|
229
|
+
timestamp: new Date(data.timestamp as string),
|
|
230
|
+
};
|
|
231
|
+
// Same object, three destinations (e.g. Postgres + TypeORM DB + MongoDB)
|
|
232
|
+
await Promise.all([
|
|
233
|
+
prisma.systemLog.create({ data: row }),
|
|
234
|
+
getRepository(TypeOrmSystemLog).save(row),
|
|
235
|
+
SystemLogModel.create(row),
|
|
236
|
+
]);
|
|
184
237
|
},
|
|
185
238
|
}),
|
|
186
239
|
});
|
|
187
240
|
```
|
|
188
241
|
|
|
189
|
-
|
|
242
|
+
Use one transport and one executor; add or remove destinations in that same block. Use this transport in your `init()` (e.g. in `logger.transports` or `logger.transportList` + `logger.env`).
|
|
190
243
|
|
|
191
244
|
---
|
|
192
245
|
|
|
@@ -569,6 +622,17 @@ Secure this route (e.g. auth, internal only). When debugging in a POD is finishe
|
|
|
569
622
|
|
|
570
623
|
## Security & Compliance
|
|
571
624
|
|
|
625
|
+
**Network & URLs:** This package does not contact any external URLs or IPs at runtime. The only network I/O is what you configure (e.g. your `executor` sending logs to your PostgreSQL, Elasticsearch, or API). URLs in this README and in `package.json` are documentation and metadata only (badges, repository links); they are not used for outbound connections.
|
|
626
|
+
|
|
627
|
+
**Environment variables:** The main package does not read any. The optional native addon (`syntropylog-native`) reads only `PATH` on Linux to locate the `ldd` binary for musl/glibc detection. No credentials or other env vars are read. See [SECURITY.md](./SECURITY.md) for the full list.
|
|
628
|
+
|
|
629
|
+
**Dynamic require:** The package does not use dynamic `require(variable)` or user-controlled paths. Module paths are static string literals (e.g. `require('syntropylog-native')`, `require('./index.js')`). The native addon loader chooses one of several fixed `.node` paths based on platform/arch; no user input is used to build require paths.
|
|
630
|
+
|
|
631
|
+
**Filesystem access:** The package only reads the files described below; it does not scan or read arbitrary paths.
|
|
632
|
+
|
|
633
|
+
- **Native addon loader** (`syntropylog-native`): Reads only (1) the presence of native `.node` binaries inside the package’s own directory (`__dirname`) to choose the correct build for the current OS/arch, and (2) on Linux only, the system `ldd` binary (e.g. `/usr/bin/ldd`) to detect musl vs glibc. No user or application files are read.
|
|
634
|
+
- **Config loader** (`loadLoggerConfig`): Reads only paths you control. If you use it, it reads at most one file: either the path you pass in `opts.configPath`, or a file under `opts.configDir` with a name derived from `opts.defaultBase` and `opts.environment` (default: `./config/logger.yaml` or `./config/logger-{env}.yaml`). You can avoid filesystem access entirely by not calling `loadLoggerConfig` and passing config directly to `init()`.
|
|
635
|
+
|
|
572
636
|
| Dynamically configurable | Fixed at init |
|
|
573
637
|
|--------------------------|---------------|
|
|
574
638
|
| Log level, additive masking rules, transports (debug: add console only for visual help in a POD; existing stay; `resetTransports()` to remove added) | Core masking config (`maskChar`, `maxDepth`), Redis/HTTP/broker |
|
package/dist/index.cjs
CHANGED
|
@@ -863,6 +863,7 @@ const validateLoggerOptions = object({
|
|
|
863
863
|
prettyPrint: optional(object({
|
|
864
864
|
enabled: optional(isBoolean),
|
|
865
865
|
})),
|
|
866
|
+
disableNativeAddon: optional(isBoolean),
|
|
866
867
|
});
|
|
867
868
|
const validateMasking = object({
|
|
868
869
|
rules: optional(arrayOf(validateMaskingRule)),
|
|
@@ -1998,6 +1999,7 @@ class SerializationManager {
|
|
|
1998
1999
|
enableMetrics: config.enableMetrics ?? true,
|
|
1999
2000
|
sanitizeSensitiveData: config.sanitizeSensitiveData ?? true,
|
|
2000
2001
|
nativeShallow: config.nativeShallow ?? false,
|
|
2002
|
+
disableNativeAddon: config.disableNativeAddon ?? false,
|
|
2001
2003
|
sanitizationContext: {
|
|
2002
2004
|
sensitiveFields: config.sanitizationContext?.sensitiveFields ||
|
|
2003
2005
|
getDefaultSensitiveFields(),
|
|
@@ -2042,7 +2044,7 @@ class SerializationManager {
|
|
|
2042
2044
|
if (this.nativeChecked)
|
|
2043
2045
|
return this.nativeAddon;
|
|
2044
2046
|
this.nativeChecked = true;
|
|
2045
|
-
if (
|
|
2047
|
+
if (this.config.disableNativeAddon) {
|
|
2046
2048
|
this.nativeAddon = null;
|
|
2047
2049
|
return null;
|
|
2048
2050
|
}
|
|
@@ -2395,6 +2397,8 @@ class ConsoleTransport extends Transport {
|
|
|
2395
2397
|
* @file src/logger/transports/optionalChalk.ts
|
|
2396
2398
|
* @description Built-in chalk-like API using ANSI escape codes. No chalk dependency.
|
|
2397
2399
|
* Used by ClassicConsoleTransport, PrettyConsoleTransport, CompactConsoleTransport, ColorfulConsoleTransport.
|
|
2400
|
+
* Does not read process.env; pass disableColors from transport options (e.g. for NO_COLOR use
|
|
2401
|
+
* disableColors: process.env.NO_COLOR != null && process.env.NO_COLOR !== '' && process.env.NO_COLOR !== '0').
|
|
2398
2402
|
*/
|
|
2399
2403
|
const RESET = '\x1b[0m';
|
|
2400
2404
|
function wrap(s, codes) {
|
|
@@ -2426,39 +2430,45 @@ function createChain(codes) {
|
|
|
2426
2430
|
Object.defineProperty(fn, 'dim', { get: () => add(2), enumerable: true });
|
|
2427
2431
|
return fn;
|
|
2428
2432
|
}
|
|
2429
|
-
|
|
2433
|
+
function createIdentityChalk() {
|
|
2434
|
+
const identity = ((s) => s);
|
|
2435
|
+
identity.white = identity;
|
|
2436
|
+
identity.bold = identity;
|
|
2437
|
+
identity.red = identity;
|
|
2438
|
+
identity.bgRed = identity;
|
|
2439
|
+
identity.yellow = identity;
|
|
2440
|
+
identity.cyan = identity;
|
|
2441
|
+
identity.green = identity;
|
|
2442
|
+
identity.gray = identity;
|
|
2443
|
+
identity.magenta = identity;
|
|
2444
|
+
identity.blue = identity;
|
|
2445
|
+
identity.bgWhite = identity;
|
|
2446
|
+
identity.dim = identity;
|
|
2447
|
+
return identity;
|
|
2448
|
+
}
|
|
2449
|
+
let cachedWithColors = null;
|
|
2450
|
+
let cachedNoColors = null;
|
|
2430
2451
|
/**
|
|
2431
2452
|
* Returns a chalk-like instance using built-in ANSI colors. No external chalk dependency.
|
|
2432
|
-
*
|
|
2453
|
+
* Does not read process.env. Pass disableColors from transport options; when true, output has no colors.
|
|
2454
|
+
* When false, colors are used only if stdout is a TTY. To respect NO_COLOR, pass
|
|
2455
|
+
* disableColors: process.env.NO_COLOR != null && process.env.NO_COLOR !== '' && process.env.NO_COLOR !== '0'.
|
|
2433
2456
|
*/
|
|
2434
|
-
function getOptionalChalk() {
|
|
2435
|
-
if (
|
|
2436
|
-
|
|
2457
|
+
function getOptionalChalk(disableColors) {
|
|
2458
|
+
if (disableColors) {
|
|
2459
|
+
if (cachedNoColors === null)
|
|
2460
|
+
cachedNoColors = createIdentityChalk();
|
|
2461
|
+
return cachedNoColors;
|
|
2437
2462
|
}
|
|
2438
|
-
const noColor = process.env.NO_COLOR !== undefined &&
|
|
2439
|
-
process.env.NO_COLOR !== '' &&
|
|
2440
|
-
process.env.NO_COLOR !== '0';
|
|
2441
2463
|
const isTTY = typeof process.stdout?.isTTY === 'boolean' && process.stdout.isTTY;
|
|
2442
|
-
if (
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
identity.green = identity;
|
|
2451
|
-
identity.gray = identity;
|
|
2452
|
-
identity.magenta = identity;
|
|
2453
|
-
identity.blue = identity;
|
|
2454
|
-
identity.bgWhite = identity;
|
|
2455
|
-
identity.dim = identity;
|
|
2456
|
-
cached = identity;
|
|
2457
|
-
}
|
|
2458
|
-
else {
|
|
2459
|
-
cached = createChain([]);
|
|
2460
|
-
}
|
|
2461
|
-
return cached;
|
|
2464
|
+
if (!isTTY) {
|
|
2465
|
+
if (cachedNoColors === null)
|
|
2466
|
+
cachedNoColors = createIdentityChalk();
|
|
2467
|
+
return cachedNoColors;
|
|
2468
|
+
}
|
|
2469
|
+
if (cachedWithColors === null)
|
|
2470
|
+
cachedWithColors = createChain([]);
|
|
2471
|
+
return cachedWithColors;
|
|
2462
2472
|
}
|
|
2463
2473
|
|
|
2464
2474
|
/**
|
|
@@ -2471,7 +2481,7 @@ function getOptionalChalk() {
|
|
|
2471
2481
|
class BaseConsolePrettyTransport extends Transport {
|
|
2472
2482
|
constructor(options) {
|
|
2473
2483
|
super(options);
|
|
2474
|
-
this.chalk = getOptionalChalk();
|
|
2484
|
+
this.chalk = getOptionalChalk(options?.disableColors ?? false);
|
|
2475
2485
|
}
|
|
2476
2486
|
/**
|
|
2477
2487
|
* The core log method. It handles common logic and delegates specific
|
|
@@ -3043,6 +3053,7 @@ class LoggerFactory {
|
|
|
3043
3053
|
this.serializationManager = new SerializationManager({
|
|
3044
3054
|
timeoutMs: config.logger?.serializerTimeoutMs,
|
|
3045
3055
|
sanitizeSensitiveData: config.masking?.enableDefaultRules !== false,
|
|
3056
|
+
disableNativeAddon: config.logger?.disableNativeAddon ?? false,
|
|
3046
3057
|
onStepError: config.onStepError,
|
|
3047
3058
|
onSerializationFallback: config.onSerializationFallback,
|
|
3048
3059
|
});
|
|
@@ -3353,6 +3364,7 @@ class LifecycleManager extends events.EventEmitter {
|
|
|
3353
3364
|
this.serializationManager = new SerializationManager({
|
|
3354
3365
|
timeoutMs: this.config.logger?.serializerTimeoutMs,
|
|
3355
3366
|
sanitizeSensitiveData: this.config.masking?.enableDefaultRules !== false,
|
|
3367
|
+
disableNativeAddon: this.config.logger?.disableNativeAddon ?? false,
|
|
3356
3368
|
onStepError: this.config.onStepError,
|
|
3357
3369
|
onSerializationFallback: this.config.onSerializationFallback,
|
|
3358
3370
|
});
|
package/dist/index.d.ts
CHANGED
|
@@ -556,6 +556,11 @@ interface TransportOptions {
|
|
|
556
556
|
* An optional name for the transport, useful for debugging.
|
|
557
557
|
*/
|
|
558
558
|
name?: string;
|
|
559
|
+
/**
|
|
560
|
+
* When true, disables ANSI colors in console output (e.g. for CI or NO_COLOR).
|
|
561
|
+
* For NO_COLOR use: disableColors: process.env.NO_COLOR != null && process.env.NO_COLOR !== '' && process.env.NO_COLOR !== '0'
|
|
562
|
+
*/
|
|
563
|
+
disableColors?: boolean;
|
|
559
564
|
}
|
|
560
565
|
/**
|
|
561
566
|
* @class Transport
|
|
@@ -619,6 +624,8 @@ interface LoggerOptions {
|
|
|
619
624
|
prettyPrint?: {
|
|
620
625
|
enabled?: boolean;
|
|
621
626
|
};
|
|
627
|
+
/** When true, the native addon is not loaded (pure JS serialization). Use for debugging or when the addon is not built. */
|
|
628
|
+
disableNativeAddon?: boolean;
|
|
622
629
|
}
|
|
623
630
|
interface MaskingConfig {
|
|
624
631
|
rules?: MaskingRule[];
|
|
@@ -715,6 +722,8 @@ interface SerializationManagerConfig {
|
|
|
715
722
|
sanitizationContext?: SanitizationConfig;
|
|
716
723
|
/** If true, Pino-style: only first level; nested objects are stringified in Node (one stringify per value). Faster for entries with complex objects; output will have nested values as JSON string. */
|
|
717
724
|
nativeShallow?: boolean;
|
|
725
|
+
/** When true, the native addon is not loaded (pure JS path). Set via logger.disableNativeAddon in init(). */
|
|
726
|
+
disableNativeAddon?: boolean;
|
|
718
727
|
/** Optional: called when a pipeline step fails (e.g. hygiene). For observability. */
|
|
719
728
|
onStepError?: (step: string, error: unknown) => void;
|
|
720
729
|
/** Optional: called when native addon fails and we fall back to JS pipeline. For observability. */
|
|
@@ -787,6 +796,8 @@ declare class ConsoleTransport extends Transport {
|
|
|
787
796
|
* @file src/logger/transports/optionalChalk.ts
|
|
788
797
|
* @description Built-in chalk-like API using ANSI escape codes. No chalk dependency.
|
|
789
798
|
* Used by ClassicConsoleTransport, PrettyConsoleTransport, CompactConsoleTransport, ColorfulConsoleTransport.
|
|
799
|
+
* Does not read process.env; pass disableColors from transport options (e.g. for NO_COLOR use
|
|
800
|
+
* disableColors: process.env.NO_COLOR != null && process.env.NO_COLOR !== '' && process.env.NO_COLOR !== '0').
|
|
790
801
|
*/
|
|
791
802
|
/** Chalk-like API: chainable style that returns wrapped string when called. */
|
|
792
803
|
type ChalkLike = {
|
|
@@ -808,7 +819,7 @@ type ChalkLike = {
|
|
|
808
819
|
/**
|
|
809
820
|
* @file src/logger/transports/BaseConsolePrettyTransport.ts
|
|
810
821
|
* @description An abstract base class for console transports that provide colored, human-readable output.
|
|
811
|
-
* Colors use built-in ANSI (no chalk dependency). Disabled when
|
|
822
|
+
* Colors use built-in ANSI (no chalk dependency). Disabled when options.disableColors is true or stdout is not a TTY.
|
|
812
823
|
*/
|
|
813
824
|
|
|
814
825
|
/**
|
package/dist/index.mjs
CHANGED
|
@@ -841,6 +841,7 @@ const validateLoggerOptions = object({
|
|
|
841
841
|
prettyPrint: optional(object({
|
|
842
842
|
enabled: optional(isBoolean),
|
|
843
843
|
})),
|
|
844
|
+
disableNativeAddon: optional(isBoolean),
|
|
844
845
|
});
|
|
845
846
|
const validateMasking = object({
|
|
846
847
|
rules: optional(arrayOf(validateMaskingRule)),
|
|
@@ -1976,6 +1977,7 @@ class SerializationManager {
|
|
|
1976
1977
|
enableMetrics: config.enableMetrics ?? true,
|
|
1977
1978
|
sanitizeSensitiveData: config.sanitizeSensitiveData ?? true,
|
|
1978
1979
|
nativeShallow: config.nativeShallow ?? false,
|
|
1980
|
+
disableNativeAddon: config.disableNativeAddon ?? false,
|
|
1979
1981
|
sanitizationContext: {
|
|
1980
1982
|
sensitiveFields: config.sanitizationContext?.sensitiveFields ||
|
|
1981
1983
|
getDefaultSensitiveFields(),
|
|
@@ -2020,7 +2022,7 @@ class SerializationManager {
|
|
|
2020
2022
|
if (this.nativeChecked)
|
|
2021
2023
|
return this.nativeAddon;
|
|
2022
2024
|
this.nativeChecked = true;
|
|
2023
|
-
if (
|
|
2025
|
+
if (this.config.disableNativeAddon) {
|
|
2024
2026
|
this.nativeAddon = null;
|
|
2025
2027
|
return null;
|
|
2026
2028
|
}
|
|
@@ -2373,6 +2375,8 @@ class ConsoleTransport extends Transport {
|
|
|
2373
2375
|
* @file src/logger/transports/optionalChalk.ts
|
|
2374
2376
|
* @description Built-in chalk-like API using ANSI escape codes. No chalk dependency.
|
|
2375
2377
|
* Used by ClassicConsoleTransport, PrettyConsoleTransport, CompactConsoleTransport, ColorfulConsoleTransport.
|
|
2378
|
+
* Does not read process.env; pass disableColors from transport options (e.g. for NO_COLOR use
|
|
2379
|
+
* disableColors: process.env.NO_COLOR != null && process.env.NO_COLOR !== '' && process.env.NO_COLOR !== '0').
|
|
2376
2380
|
*/
|
|
2377
2381
|
const RESET = '\x1b[0m';
|
|
2378
2382
|
function wrap(s, codes) {
|
|
@@ -2404,39 +2408,45 @@ function createChain(codes) {
|
|
|
2404
2408
|
Object.defineProperty(fn, 'dim', { get: () => add(2), enumerable: true });
|
|
2405
2409
|
return fn;
|
|
2406
2410
|
}
|
|
2407
|
-
|
|
2411
|
+
function createIdentityChalk() {
|
|
2412
|
+
const identity = ((s) => s);
|
|
2413
|
+
identity.white = identity;
|
|
2414
|
+
identity.bold = identity;
|
|
2415
|
+
identity.red = identity;
|
|
2416
|
+
identity.bgRed = identity;
|
|
2417
|
+
identity.yellow = identity;
|
|
2418
|
+
identity.cyan = identity;
|
|
2419
|
+
identity.green = identity;
|
|
2420
|
+
identity.gray = identity;
|
|
2421
|
+
identity.magenta = identity;
|
|
2422
|
+
identity.blue = identity;
|
|
2423
|
+
identity.bgWhite = identity;
|
|
2424
|
+
identity.dim = identity;
|
|
2425
|
+
return identity;
|
|
2426
|
+
}
|
|
2427
|
+
let cachedWithColors = null;
|
|
2428
|
+
let cachedNoColors = null;
|
|
2408
2429
|
/**
|
|
2409
2430
|
* Returns a chalk-like instance using built-in ANSI colors. No external chalk dependency.
|
|
2410
|
-
*
|
|
2431
|
+
* Does not read process.env. Pass disableColors from transport options; when true, output has no colors.
|
|
2432
|
+
* When false, colors are used only if stdout is a TTY. To respect NO_COLOR, pass
|
|
2433
|
+
* disableColors: process.env.NO_COLOR != null && process.env.NO_COLOR !== '' && process.env.NO_COLOR !== '0'.
|
|
2411
2434
|
*/
|
|
2412
|
-
function getOptionalChalk() {
|
|
2413
|
-
if (
|
|
2414
|
-
|
|
2435
|
+
function getOptionalChalk(disableColors) {
|
|
2436
|
+
if (disableColors) {
|
|
2437
|
+
if (cachedNoColors === null)
|
|
2438
|
+
cachedNoColors = createIdentityChalk();
|
|
2439
|
+
return cachedNoColors;
|
|
2415
2440
|
}
|
|
2416
|
-
const noColor = process.env.NO_COLOR !== undefined &&
|
|
2417
|
-
process.env.NO_COLOR !== '' &&
|
|
2418
|
-
process.env.NO_COLOR !== '0';
|
|
2419
2441
|
const isTTY = typeof process.stdout?.isTTY === 'boolean' && process.stdout.isTTY;
|
|
2420
|
-
if (
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
identity.green = identity;
|
|
2429
|
-
identity.gray = identity;
|
|
2430
|
-
identity.magenta = identity;
|
|
2431
|
-
identity.blue = identity;
|
|
2432
|
-
identity.bgWhite = identity;
|
|
2433
|
-
identity.dim = identity;
|
|
2434
|
-
cached = identity;
|
|
2435
|
-
}
|
|
2436
|
-
else {
|
|
2437
|
-
cached = createChain([]);
|
|
2438
|
-
}
|
|
2439
|
-
return cached;
|
|
2442
|
+
if (!isTTY) {
|
|
2443
|
+
if (cachedNoColors === null)
|
|
2444
|
+
cachedNoColors = createIdentityChalk();
|
|
2445
|
+
return cachedNoColors;
|
|
2446
|
+
}
|
|
2447
|
+
if (cachedWithColors === null)
|
|
2448
|
+
cachedWithColors = createChain([]);
|
|
2449
|
+
return cachedWithColors;
|
|
2440
2450
|
}
|
|
2441
2451
|
|
|
2442
2452
|
/**
|
|
@@ -2449,7 +2459,7 @@ function getOptionalChalk() {
|
|
|
2449
2459
|
class BaseConsolePrettyTransport extends Transport {
|
|
2450
2460
|
constructor(options) {
|
|
2451
2461
|
super(options);
|
|
2452
|
-
this.chalk = getOptionalChalk();
|
|
2462
|
+
this.chalk = getOptionalChalk(options?.disableColors ?? false);
|
|
2453
2463
|
}
|
|
2454
2464
|
/**
|
|
2455
2465
|
* The core log method. It handles common logic and delegates specific
|
|
@@ -3021,6 +3031,7 @@ class LoggerFactory {
|
|
|
3021
3031
|
this.serializationManager = new SerializationManager({
|
|
3022
3032
|
timeoutMs: config.logger?.serializerTimeoutMs,
|
|
3023
3033
|
sanitizeSensitiveData: config.masking?.enableDefaultRules !== false,
|
|
3034
|
+
disableNativeAddon: config.logger?.disableNativeAddon ?? false,
|
|
3024
3035
|
onStepError: config.onStepError,
|
|
3025
3036
|
onSerializationFallback: config.onSerializationFallback,
|
|
3026
3037
|
});
|
|
@@ -3331,6 +3342,7 @@ class LifecycleManager extends EventEmitter {
|
|
|
3331
3342
|
this.serializationManager = new SerializationManager({
|
|
3332
3343
|
timeoutMs: this.config.logger?.serializerTimeoutMs,
|
|
3333
3344
|
sanitizeSensitiveData: this.config.masking?.enableDefaultRules !== false,
|
|
3345
|
+
disableNativeAddon: this.config.logger?.disableNativeAddon ?? false,
|
|
3334
3346
|
onStepError: this.config.onStepError,
|
|
3335
3347
|
onSerializationFallback: this.config.onSerializationFallback,
|
|
3336
3348
|
});
|
package/dist/testing/index.d.ts
CHANGED
|
@@ -351,6 +351,11 @@ interface TransportOptions {
|
|
|
351
351
|
* An optional name for the transport, useful for debugging.
|
|
352
352
|
*/
|
|
353
353
|
name?: string;
|
|
354
|
+
/**
|
|
355
|
+
* When true, disables ANSI colors in console output (e.g. for CI or NO_COLOR).
|
|
356
|
+
* For NO_COLOR use: disableColors: process.env.NO_COLOR != null && process.env.NO_COLOR !== '' && process.env.NO_COLOR !== '0'
|
|
357
|
+
*/
|
|
358
|
+
disableColors?: boolean;
|
|
354
359
|
}
|
|
355
360
|
/**
|
|
356
361
|
* @class Transport
|
|
@@ -37,7 +37,9 @@ export interface LoggerConfigLoaderOptions {
|
|
|
37
37
|
*
|
|
38
38
|
* **Security:** A restricted schema (JSON_SCHEMA) is used to avoid prototype pollution
|
|
39
39
|
* and dangerous types. Only use with configuration files under deployment team
|
|
40
|
-
* control (controlled paths and permissions).
|
|
40
|
+
* control (controlled paths and permissions). This function reads only the paths
|
|
41
|
+
* derived from opts (configPath, configDir, defaultBase, environment); no other
|
|
42
|
+
* filesystem access is performed.
|
|
41
43
|
*
|
|
42
44
|
* @param opts - Options to customize the loading behavior.
|
|
43
45
|
* @returns A partial `LoggerOptions` object, or an empty object if no file is found.
|
|
@@ -23,6 +23,8 @@ export interface LoggerOptions {
|
|
|
23
23
|
prettyPrint?: {
|
|
24
24
|
enabled?: boolean;
|
|
25
25
|
};
|
|
26
|
+
/** When true, the native addon is not loaded (pure JS serialization). Use for debugging or when the addon is not built. */
|
|
27
|
+
disableNativeAddon?: boolean;
|
|
26
28
|
}
|
|
27
29
|
export interface MaskingConfig {
|
|
28
30
|
rules?: MaskingRule[];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file src/logger/transports/BaseConsolePrettyTransport.ts
|
|
3
3
|
* @description An abstract base class for console transports that provide colored, human-readable output.
|
|
4
|
-
* Colors use built-in ANSI (no chalk dependency). Disabled when
|
|
4
|
+
* Colors use built-in ANSI (no chalk dependency). Disabled when options.disableColors is true or stdout is not a TTY.
|
|
5
5
|
*/
|
|
6
6
|
import { LogEntry } from '../../types';
|
|
7
7
|
import { LogLevel } from '../levels';
|
|
@@ -30,6 +30,11 @@ export interface TransportOptions {
|
|
|
30
30
|
* An optional name for the transport, useful for debugging.
|
|
31
31
|
*/
|
|
32
32
|
name?: string;
|
|
33
|
+
/**
|
|
34
|
+
* When true, disables ANSI colors in console output (e.g. for CI or NO_COLOR).
|
|
35
|
+
* For NO_COLOR use: disableColors: process.env.NO_COLOR != null && process.env.NO_COLOR !== '' && process.env.NO_COLOR !== '0'
|
|
36
|
+
*/
|
|
37
|
+
disableColors?: boolean;
|
|
33
38
|
}
|
|
34
39
|
/**
|
|
35
40
|
* @class Transport
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
* @file src/logger/transports/optionalChalk.ts
|
|
3
3
|
* @description Built-in chalk-like API using ANSI escape codes. No chalk dependency.
|
|
4
4
|
* Used by ClassicConsoleTransport, PrettyConsoleTransport, CompactConsoleTransport, ColorfulConsoleTransport.
|
|
5
|
+
* Does not read process.env; pass disableColors from transport options (e.g. for NO_COLOR use
|
|
6
|
+
* disableColors: process.env.NO_COLOR != null && process.env.NO_COLOR !== '' && process.env.NO_COLOR !== '0').
|
|
5
7
|
*/
|
|
6
8
|
/** Chalk-like API: chainable style that returns wrapped string when called. */
|
|
7
9
|
export type ChalkLike = {
|
|
@@ -21,6 +23,8 @@ export type ChalkLike = {
|
|
|
21
23
|
};
|
|
22
24
|
/**
|
|
23
25
|
* Returns a chalk-like instance using built-in ANSI colors. No external chalk dependency.
|
|
24
|
-
*
|
|
26
|
+
* Does not read process.env. Pass disableColors from transport options; when true, output has no colors.
|
|
27
|
+
* When false, colors are used only if stdout is a TTY. To respect NO_COLOR, pass
|
|
28
|
+
* disableColors: process.env.NO_COLOR != null && process.env.NO_COLOR !== '' && process.env.NO_COLOR !== '0'.
|
|
25
29
|
*/
|
|
26
|
-
export declare function getOptionalChalk(): ChalkLike;
|
|
30
|
+
export declare function getOptionalChalk(disableColors: boolean): ChalkLike;
|
|
@@ -15,6 +15,8 @@ export interface SerializationManagerConfig {
|
|
|
15
15
|
sanitizationContext?: SanitizationConfig;
|
|
16
16
|
/** If true, Pino-style: only first level; nested objects are stringified in Node (one stringify per value). Faster for entries with complex objects; output will have nested values as JSON string. */
|
|
17
17
|
nativeShallow?: boolean;
|
|
18
|
+
/** When true, the native addon is not loaded (pure JS path). Set via logger.disableNativeAddon in init(). */
|
|
19
|
+
disableNativeAddon?: boolean;
|
|
18
20
|
/** Optional: called when a pipeline step fails (e.g. hygiene). For observability. */
|
|
19
21
|
onStepError?: (step: string, error: unknown) => void;
|
|
20
22
|
/** Optional: called when native addon fails and we fall back to JS pipeline. For observability. */
|