plslog 1.0.0 → 1.1.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.mts CHANGED
@@ -1,34 +1,179 @@
1
1
  type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'none';
2
+ type FilterMode = 'redact' | 'hide' | 'type' | 'length';
3
+ type FilterFieldPredicate = (key: string, value: any, path: string[]) => boolean;
4
+ type FilterFieldConfig = string | RegExp | FilterFieldPredicate;
5
+ interface DedupConfig {
6
+ enabled: boolean;
7
+ flushInterval?: number;
8
+ }
9
+ interface DedupEntry {
10
+ key: string;
11
+ level: LogLevel;
12
+ message: string;
13
+ args: unknown[];
14
+ count: number;
15
+ firstTimestamp: number;
16
+ lastTimestamp: number;
17
+ flushTimeoutId?: number;
18
+ filterOptions?: LogFilterOptions;
19
+ }
20
+ interface LogFilterOptions {
21
+ pick?: string[];
22
+ omit?: FilterFieldConfig[];
23
+ filterMode?: FilterMode;
24
+ filterReplacement?: string;
25
+ }
26
+ interface ErrorSerializationConfig {
27
+ includeStack?: boolean;
28
+ stackFrameLimit?: number;
29
+ includeCause?: boolean;
30
+ maxCauseDepth?: number;
31
+ sanitizeStack?: boolean;
32
+ sanitizePatterns?: RegExp[];
33
+ }
34
+ interface FormatterOptions extends LogFilterOptions {
35
+ maxDepth?: number;
36
+ filterFields?: FilterFieldConfig[];
37
+ globalFilterMode?: FilterMode;
38
+ globalFilterReplacement?: string;
39
+ errorConfig?: ErrorSerializationConfig;
40
+ }
2
41
  interface LoggerOptions {
3
42
  namespace?: string;
4
43
  level?: LogLevel;
5
44
  maxDepth?: number;
45
+ dedup?: Partial<DedupConfig>;
46
+ context?: Record<string, unknown>;
6
47
  }
7
48
  type GlobalConfig = {
8
49
  namespaces?: string;
9
50
  level?: LogLevel;
10
51
  activeLevels?: LogLevel[];
11
52
  maxDepth?: number;
53
+ dedup?: Partial<DedupConfig>;
54
+ filterFields?: FilterFieldConfig[];
55
+ filterMode?: FilterMode;
56
+ filterReplacement?: string;
57
+ errorSerialization?: ErrorSerializationConfig;
12
58
  };
59
+ interface ConditionContext {
60
+ namespace: string;
61
+ level: LogLevel;
62
+ [key: string]: unknown;
63
+ }
64
+ type Condition = boolean | ((ctx: ConditionContext) => boolean);
13
65
 
14
66
  declare class Logger {
15
67
  private _namespace;
16
68
  private _level;
17
69
  private _maxDepth;
70
+ private _dedupConfig;
71
+ private _dedupBuffer;
72
+ private _tempFilterOptions;
73
+ private _context;
74
+ private _tempConditions;
18
75
  constructor(options?: LoggerOptions);
19
76
  debug(message: string, ...args: unknown[]): this;
20
77
  info(message: string, ...args: unknown[]): this;
21
78
  warn(message: string, ...args: unknown[]): this;
22
79
  error(message: string, ...args: unknown[]): this;
80
+ /**
81
+ * Assert that a condition is truthy. Logs an error if the condition is falsy.
82
+ * Similar to console.assert() but integrates with plslog's features.
83
+ * Uses JavaScript truthiness - falsy values: false, 0, '', null, undefined, NaN
84
+ *
85
+ * @param condition - The condition to assert (uses JavaScript truthiness)
86
+ * @param message - Error message to log if assertion fails
87
+ * @param args - Additional arguments to log
88
+ * @returns this for chaining
89
+ *
90
+ * @example
91
+ * logger.assert(user !== null, 'User should not be null', user);
92
+ * logger.assert(count > 0, 'Count must be positive', { count });
93
+ * logger.assert(data, 'Data is required'); // Checks if data is truthy
94
+ */
95
+ assert(condition: unknown, message: string, ...args: unknown[]): this;
23
96
  setLevel(level: LogLevel): void;
97
+ /**
98
+ * Set the namespace for this logger instance
99
+ * Returns this for method chaining
100
+ *
101
+ * @param namespace - The namespace string (e.g., 'service:api', 'component')
102
+ * @returns this for chaining
103
+ *
104
+ * @example
105
+ * const log = logger().namespace('service:api');
106
+ * log.debug('Message'); // Logs with namespace 'service:api'
107
+ *
108
+ * // Can also be called after instantiation
109
+ * const log2 = logger();
110
+ * log2.namespace('component').debug('Message');
111
+ */
112
+ namespace(namespace: string): this;
24
113
  maxDepth(maxDepth: number): this;
114
+ /**
115
+ * Pick only specific fields to log (whitelist approach)
116
+ * Supports dot notation for nested fields: 'user.name', 'user.email'
117
+ * Supports wildcards: 'user.*' matches all fields under user
118
+ */
119
+ pick(fields: string[]): this;
120
+ /**
121
+ * Omit specific fields from logging (blacklist approach)
122
+ * Supports strings, regex patterns, and predicate functions
123
+ */
124
+ omit(fields: FilterFieldConfig[]): this;
125
+ /**
126
+ * Set filter mode for per-log filtering
127
+ * - 'redact': Replace with custom string (default: '***REDACTED***')
128
+ * - 'hide': Remove field completely
129
+ * - 'type': Show type info like '[string]', '[Array(3)]'
130
+ * - 'length': Show length info like '[8 chars]', '[3 items]'
131
+ */
132
+ filterMode(mode: FilterMode, replacement?: string): this;
133
+ once(enabled?: boolean): this;
134
+ flushDedup(): this;
135
+ /**
136
+ * Execute log only if condition is true
137
+ * Supports boolean values or predicate functions
138
+ * Multiple when() calls are AND-ed together
139
+ *
140
+ * @example
141
+ * // Boolean condition
142
+ * logger.when(isDev).debug('Dev only');
143
+ *
144
+ * // Predicate with context
145
+ * logger.when(ctx => ctx.namespace === 'auth').debug('Auth log');
146
+ *
147
+ * // Chaining (both must be true)
148
+ * logger
149
+ * .when(ctx => ctx.level === 'debug')
150
+ * .when(isDevMode)
151
+ * .debug('Conditional');
152
+ */
153
+ when(condition: Condition): this;
154
+ /**
155
+ * Execute log only if condition is false (inverse of when)
156
+ * Supports boolean values or predicate functions
157
+ *
158
+ * @example
159
+ * // Boolean condition
160
+ * logger.unless(isProd).debug('Not in production');
161
+ *
162
+ * // Predicate with context
163
+ * logger.unless(ctx => ctx.level === 'error').info('Non-error log');
164
+ */
165
+ unless(condition: Condition): this;
25
166
  private getLevelPriority;
26
167
  private log;
168
+ private logWithDedup;
169
+ private flushDedupEntry;
170
+ private formatTimestamp;
171
+ private logImmediate;
27
172
  }
28
173
  type Plslog = {
29
- (options?: LoggerOptions): Logger;
174
+ (options?: LoggerOptions | string): Logger;
30
175
  configure(options: GlobalConfig): void;
31
176
  };
32
177
  declare const plslog: Plslog;
33
178
 
34
- export { type GlobalConfig, type LogLevel, type LoggerOptions, plslog as default };
179
+ export { type Condition, type ConditionContext, type DedupConfig, type DedupEntry, type ErrorSerializationConfig, type FilterFieldConfig, type FilterFieldPredicate, type FilterMode, type FormatterOptions, type GlobalConfig, type LogFilterOptions, type LogLevel, type LoggerOptions, plslog as default };
package/dist/index.d.ts CHANGED
@@ -1,34 +1,179 @@
1
1
  type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'none';
2
+ type FilterMode = 'redact' | 'hide' | 'type' | 'length';
3
+ type FilterFieldPredicate = (key: string, value: any, path: string[]) => boolean;
4
+ type FilterFieldConfig = string | RegExp | FilterFieldPredicate;
5
+ interface DedupConfig {
6
+ enabled: boolean;
7
+ flushInterval?: number;
8
+ }
9
+ interface DedupEntry {
10
+ key: string;
11
+ level: LogLevel;
12
+ message: string;
13
+ args: unknown[];
14
+ count: number;
15
+ firstTimestamp: number;
16
+ lastTimestamp: number;
17
+ flushTimeoutId?: number;
18
+ filterOptions?: LogFilterOptions;
19
+ }
20
+ interface LogFilterOptions {
21
+ pick?: string[];
22
+ omit?: FilterFieldConfig[];
23
+ filterMode?: FilterMode;
24
+ filterReplacement?: string;
25
+ }
26
+ interface ErrorSerializationConfig {
27
+ includeStack?: boolean;
28
+ stackFrameLimit?: number;
29
+ includeCause?: boolean;
30
+ maxCauseDepth?: number;
31
+ sanitizeStack?: boolean;
32
+ sanitizePatterns?: RegExp[];
33
+ }
34
+ interface FormatterOptions extends LogFilterOptions {
35
+ maxDepth?: number;
36
+ filterFields?: FilterFieldConfig[];
37
+ globalFilterMode?: FilterMode;
38
+ globalFilterReplacement?: string;
39
+ errorConfig?: ErrorSerializationConfig;
40
+ }
2
41
  interface LoggerOptions {
3
42
  namespace?: string;
4
43
  level?: LogLevel;
5
44
  maxDepth?: number;
45
+ dedup?: Partial<DedupConfig>;
46
+ context?: Record<string, unknown>;
6
47
  }
7
48
  type GlobalConfig = {
8
49
  namespaces?: string;
9
50
  level?: LogLevel;
10
51
  activeLevels?: LogLevel[];
11
52
  maxDepth?: number;
53
+ dedup?: Partial<DedupConfig>;
54
+ filterFields?: FilterFieldConfig[];
55
+ filterMode?: FilterMode;
56
+ filterReplacement?: string;
57
+ errorSerialization?: ErrorSerializationConfig;
12
58
  };
59
+ interface ConditionContext {
60
+ namespace: string;
61
+ level: LogLevel;
62
+ [key: string]: unknown;
63
+ }
64
+ type Condition = boolean | ((ctx: ConditionContext) => boolean);
13
65
 
14
66
  declare class Logger {
15
67
  private _namespace;
16
68
  private _level;
17
69
  private _maxDepth;
70
+ private _dedupConfig;
71
+ private _dedupBuffer;
72
+ private _tempFilterOptions;
73
+ private _context;
74
+ private _tempConditions;
18
75
  constructor(options?: LoggerOptions);
19
76
  debug(message: string, ...args: unknown[]): this;
20
77
  info(message: string, ...args: unknown[]): this;
21
78
  warn(message: string, ...args: unknown[]): this;
22
79
  error(message: string, ...args: unknown[]): this;
80
+ /**
81
+ * Assert that a condition is truthy. Logs an error if the condition is falsy.
82
+ * Similar to console.assert() but integrates with plslog's features.
83
+ * Uses JavaScript truthiness - falsy values: false, 0, '', null, undefined, NaN
84
+ *
85
+ * @param condition - The condition to assert (uses JavaScript truthiness)
86
+ * @param message - Error message to log if assertion fails
87
+ * @param args - Additional arguments to log
88
+ * @returns this for chaining
89
+ *
90
+ * @example
91
+ * logger.assert(user !== null, 'User should not be null', user);
92
+ * logger.assert(count > 0, 'Count must be positive', { count });
93
+ * logger.assert(data, 'Data is required'); // Checks if data is truthy
94
+ */
95
+ assert(condition: unknown, message: string, ...args: unknown[]): this;
23
96
  setLevel(level: LogLevel): void;
97
+ /**
98
+ * Set the namespace for this logger instance
99
+ * Returns this for method chaining
100
+ *
101
+ * @param namespace - The namespace string (e.g., 'service:api', 'component')
102
+ * @returns this for chaining
103
+ *
104
+ * @example
105
+ * const log = logger().namespace('service:api');
106
+ * log.debug('Message'); // Logs with namespace 'service:api'
107
+ *
108
+ * // Can also be called after instantiation
109
+ * const log2 = logger();
110
+ * log2.namespace('component').debug('Message');
111
+ */
112
+ namespace(namespace: string): this;
24
113
  maxDepth(maxDepth: number): this;
114
+ /**
115
+ * Pick only specific fields to log (whitelist approach)
116
+ * Supports dot notation for nested fields: 'user.name', 'user.email'
117
+ * Supports wildcards: 'user.*' matches all fields under user
118
+ */
119
+ pick(fields: string[]): this;
120
+ /**
121
+ * Omit specific fields from logging (blacklist approach)
122
+ * Supports strings, regex patterns, and predicate functions
123
+ */
124
+ omit(fields: FilterFieldConfig[]): this;
125
+ /**
126
+ * Set filter mode for per-log filtering
127
+ * - 'redact': Replace with custom string (default: '***REDACTED***')
128
+ * - 'hide': Remove field completely
129
+ * - 'type': Show type info like '[string]', '[Array(3)]'
130
+ * - 'length': Show length info like '[8 chars]', '[3 items]'
131
+ */
132
+ filterMode(mode: FilterMode, replacement?: string): this;
133
+ once(enabled?: boolean): this;
134
+ flushDedup(): this;
135
+ /**
136
+ * Execute log only if condition is true
137
+ * Supports boolean values or predicate functions
138
+ * Multiple when() calls are AND-ed together
139
+ *
140
+ * @example
141
+ * // Boolean condition
142
+ * logger.when(isDev).debug('Dev only');
143
+ *
144
+ * // Predicate with context
145
+ * logger.when(ctx => ctx.namespace === 'auth').debug('Auth log');
146
+ *
147
+ * // Chaining (both must be true)
148
+ * logger
149
+ * .when(ctx => ctx.level === 'debug')
150
+ * .when(isDevMode)
151
+ * .debug('Conditional');
152
+ */
153
+ when(condition: Condition): this;
154
+ /**
155
+ * Execute log only if condition is false (inverse of when)
156
+ * Supports boolean values or predicate functions
157
+ *
158
+ * @example
159
+ * // Boolean condition
160
+ * logger.unless(isProd).debug('Not in production');
161
+ *
162
+ * // Predicate with context
163
+ * logger.unless(ctx => ctx.level === 'error').info('Non-error log');
164
+ */
165
+ unless(condition: Condition): this;
25
166
  private getLevelPriority;
26
167
  private log;
168
+ private logWithDedup;
169
+ private flushDedupEntry;
170
+ private formatTimestamp;
171
+ private logImmediate;
27
172
  }
28
173
  type Plslog = {
29
- (options?: LoggerOptions): Logger;
174
+ (options?: LoggerOptions | string): Logger;
30
175
  configure(options: GlobalConfig): void;
31
176
  };
32
177
  declare const plslog: Plslog;
33
178
 
34
- export { type GlobalConfig, type LogLevel, type LoggerOptions, plslog as default };
179
+ export { type Condition, type ConditionContext, type DedupConfig, type DedupEntry, type ErrorSerializationConfig, type FilterFieldConfig, type FilterFieldPredicate, type FilterMode, type FormatterOptions, type GlobalConfig, type LogFilterOptions, type LogLevel, type LoggerOptions, plslog as default };