@abdokouta/react-logger 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,559 @@
1
+ # @abdokouta/logger
2
+
3
+ Laravel-inspired logging system for Refine with multiple channels, transporters, and formatters.
4
+
5
+ ## Features
6
+
7
+ - **Multiple Channels**: Console, Storage (localStorage), and Silent
8
+ - **Pluggable Transporters**: Route logs to different destinations
9
+ - **Customizable Formatters**: Pretty (with colors/emoji), JSON, or Simple
10
+ - **Contextual Logging**: Add persistent context to all logs
11
+ - **React Hooks**: `useLogger()` and `useLoggerContext()` for easy integration
12
+ - **TypeScript**: Full type safety with comprehensive JSDoc documentation
13
+ - **Browser Compatible**: Works in all modern browsers
14
+ - **Dependency Injection**: Integrates with @abdokouta/container
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install @abdokouta/logger
20
+ # or
21
+ yarn add @abdokouta/logger
22
+ # or
23
+ pnpm add @abdokouta/logger
24
+ ```
25
+
26
+ ## Quick Start
27
+
28
+ ### 1. Configure the Module
29
+
30
+ ```typescript
31
+ import { Module } from '@abdokouta/container';
32
+ import { LoggerModule, defineConfig } from '@abdokouta/logger';
33
+ import { ConsoleTransporter, StorageTransporter } from '@abdokouta/logger';
34
+ import { LogLevel } from '@abdokouta/logger';
35
+
36
+ @Module({
37
+ imports: [
38
+ LoggerModule.forRoot(
39
+ defineConfig({
40
+ default: 'console',
41
+ channels: {
42
+ console: {
43
+ transporters: [new ConsoleTransporter()],
44
+ context: { app: 'my-app', env: 'production' },
45
+ },
46
+ storage: {
47
+ transporters: [new StorageTransporter({ maxEntries: 500 })],
48
+ },
49
+ errors: {
50
+ transporters: [
51
+ new ConsoleTransporter({ level: LogLevel.Error }),
52
+ new StorageTransporter({ key: 'error-logs' }),
53
+ ],
54
+ },
55
+ },
56
+ })
57
+ ),
58
+ ],
59
+ })
60
+ export class AppModule {}
61
+ ```
62
+
63
+ ### 2. Use in Services
64
+
65
+ ```typescript
66
+ import { Injectable, Inject } from '@abdokouta/container';
67
+ import { LoggerService } from '@abdokouta/logger';
68
+
69
+ @Injectable()
70
+ export class UserService {
71
+ constructor(
72
+ @Inject(LoggerService) private logger: LoggerService
73
+ ) {}
74
+
75
+ async createUser(data: UserData) {
76
+ this.logger.info('Creating user', { email: data.email });
77
+
78
+ try {
79
+ const user = await this.db.users.create(data);
80
+ this.logger.info('User created', { userId: user.id });
81
+ return user;
82
+ } catch (error) {
83
+ this.logger.error('Failed to create user', { error });
84
+ throw error;
85
+ }
86
+ }
87
+
88
+ async auditAction(action: string) {
89
+ // Use specific channel
90
+ const auditLogger = this.logger.channel('audit');
91
+ auditLogger.info('User action', { action });
92
+ }
93
+ }
94
+ ```
95
+
96
+ ### 3. Use in React Components
97
+
98
+ ```typescript
99
+ import { useLogger } from '@abdokouta/logger';
100
+
101
+ function MyComponent() {
102
+ const logger = useLogger();
103
+
104
+ const handleClick = () => {
105
+ logger.info('Button clicked', { timestamp: Date.now() });
106
+ };
107
+
108
+ return <button onClick={handleClick}>Click me</button>;
109
+ }
110
+ ```
111
+
112
+ ## Configuration
113
+
114
+ ### LoggerModuleOptions
115
+
116
+ ```typescript
117
+ interface LoggerModuleOptions {
118
+ /** Default channel name */
119
+ default: string;
120
+
121
+ /** Channel configurations */
122
+ channels: Record<string, LoggerConfig>;
123
+ }
124
+
125
+ interface LoggerConfig {
126
+ /** Transporters for this channel */
127
+ transporters?: TransporterInterface[];
128
+
129
+ /** Initial shared context */
130
+ context?: Record<string, unknown>;
131
+ }
132
+ ```
133
+
134
+ ### Using defineConfig
135
+
136
+ ```typescript
137
+ import { defineConfig } from '@abdokouta/logger';
138
+
139
+ export const loggerConfig = defineConfig({
140
+ default: 'console',
141
+ channels: {
142
+ console: {
143
+ transporters: [new ConsoleTransporter()],
144
+ context: { app: 'my-app' },
145
+ },
146
+ },
147
+ });
148
+ ```
149
+
150
+ ### Using Presets
151
+
152
+ ```typescript
153
+ import { defineConfig, consolePreset, silentPreset } from '@abdokouta/logger';
154
+
155
+ // Console preset (development)
156
+ export const devConfig = defineConfig({
157
+ ...consolePreset,
158
+ channels: {
159
+ ...consolePreset.channels,
160
+ console: {
161
+ ...consolePreset.channels.console,
162
+ context: { app: 'my-app', env: 'dev' },
163
+ },
164
+ },
165
+ });
166
+
167
+ // Silent preset (testing)
168
+ export const testConfig = defineConfig(silentPreset);
169
+ ```
170
+
171
+ ## Channels
172
+
173
+ ### Console Channel
174
+
175
+ Logs to the browser console with colors and emoji.
176
+
177
+ ```typescript
178
+ {
179
+ console: {
180
+ transporters: [new ConsoleTransporter()],
181
+ },
182
+ }
183
+ ```
184
+
185
+ ### Storage Channel
186
+
187
+ Persists logs to localStorage.
188
+
189
+ ```typescript
190
+ {
191
+ storage: {
192
+ transporters: [
193
+ new StorageTransporter({
194
+ key: 'app-logs',
195
+ maxEntries: 500,
196
+ }),
197
+ ],
198
+ },
199
+ }
200
+ ```
201
+
202
+ ### Error Channel
203
+
204
+ Multiple transporters for error handling.
205
+
206
+ ```typescript
207
+ {
208
+ errors: {
209
+ transporters: [
210
+ new ConsoleTransporter({ level: LogLevel.Error }),
211
+ new StorageTransporter({ key: 'error-logs', maxEntries: 200 }),
212
+ ],
213
+ },
214
+ }
215
+ ```
216
+
217
+ ### Silent Channel
218
+
219
+ Disables logging (useful for testing).
220
+
221
+ ```typescript
222
+ {
223
+ silent: {
224
+ transporters: [new SilentTransporter()],
225
+ },
226
+ }
227
+ ```
228
+
229
+ ## API Reference
230
+
231
+ ### LoggerService
232
+
233
+ Main service for logging operations.
234
+
235
+ #### Methods
236
+
237
+ - `channel(name?: string): LoggerInterface` - Get a specific channel
238
+ - `debug(message, context?)` - Log debug message
239
+ - `info(message, context?)` - Log info message
240
+ - `warn(message, context?)` - Log warning message
241
+ - `error(message, context?)` - Log error message
242
+ - `fatal(message, context?)` - Log fatal message
243
+ - `withContext(context)` - Add persistent context
244
+ - `withoutContext(keys?)` - Remove context
245
+ - `getChannelNames()` - Get all channel names
246
+ - `hasChannel(name)` - Check if channel exists
247
+ - `isChannelActive(name?)` - Check if channel is active
248
+
249
+ ### Logger
250
+
251
+ Core logger class (used internally by LoggerService).
252
+
253
+ #### Methods
254
+
255
+ - `debug(message, context?)` - Log debug message
256
+ - `info(message, context?)` - Log info message
257
+ - `warn(message, context?)` - Log warning message
258
+ - `error(message, context?)` - Log error message
259
+ - `fatal(message, context?)` - Log fatal message
260
+ - `withContext(context)` - Add persistent context
261
+ - `withoutContext(keys?)` - Remove context
262
+ - `getTransporters()` - Get all transporters
263
+ - `getContext()` - Get current context
264
+
265
+ ## Transporters
266
+
267
+ ### ConsoleTransporter
268
+
269
+ Outputs to browser console with colors and emoji.
270
+
271
+ ```typescript
272
+ new ConsoleTransporter({
273
+ formatter: new PrettyFormatter(), // default
274
+ level: LogLevel.Debug, // minimum level
275
+ })
276
+ ```
277
+
278
+ ### StorageTransporter
279
+
280
+ Persists logs to localStorage.
281
+
282
+ ```typescript
283
+ new StorageTransporter({
284
+ key: 'logger:entries', // localStorage key
285
+ maxEntries: 100, // max entries to keep
286
+ formatter: new JsonFormatter(), // default
287
+ level: LogLevel.Debug, // minimum level
288
+ })
289
+ ```
290
+
291
+ ### SilentTransporter
292
+
293
+ No-op transporter (discards all logs).
294
+
295
+ ```typescript
296
+ new SilentTransporter()
297
+ ```
298
+
299
+ ## Formatters
300
+
301
+ ### PrettyFormatter
302
+
303
+ Colorful output with emoji (default for console).
304
+
305
+ ```typescript
306
+ new PrettyFormatter()
307
+ // Output: 🐛 [DEBUG] [14:30:00.000] Hello world {userId: 42}
308
+ ```
309
+
310
+ ### JsonFormatter
311
+
312
+ JSON output (default for storage).
313
+
314
+ ```typescript
315
+ new JsonFormatter()
316
+ // Output: {"level":"info","message":"Hello","timestamp":"...","context":{}}
317
+ ```
318
+
319
+ ### SimpleFormatter
320
+
321
+ Plain text output.
322
+
323
+ ```typescript
324
+ new SimpleFormatter()
325
+ // Output: [DEBUG] [2026-03-28T14:30:00.000Z] Hello world {userId: 42}
326
+ ```
327
+
328
+ ## React Hooks
329
+
330
+ ### useLogger
331
+
332
+ Access logger service in components.
333
+
334
+ ```typescript
335
+ import { useLogger } from '@abdokouta/logger';
336
+
337
+ function MyComponent() {
338
+ const logger = useLogger();
339
+
340
+ // Use default channel
341
+ logger.info('Component rendered');
342
+
343
+ // Use specific channel
344
+ const errorLogger = useLogger('errors');
345
+ errorLogger.error('Something went wrong');
346
+
347
+ return <div>Hello</div>;
348
+ }
349
+ ```
350
+
351
+ ### useLoggerContext
352
+
353
+ Manage logger context in components.
354
+
355
+ ```typescript
356
+ import { useLoggerContext, useLogger } from '@abdokouta/logger';
357
+
358
+ function UserProfile({ userId }: { userId: string }) {
359
+ // Add userId to all logs in this component
360
+ useLoggerContext({ userId, component: 'UserProfile' });
361
+
362
+ const logger = useLogger();
363
+
364
+ const handleUpdate = () => {
365
+ // This log will include { userId, component: 'UserProfile' }
366
+ logger.info('Updating profile');
367
+ };
368
+
369
+ return <button onClick={handleUpdate}>Update</button>;
370
+ }
371
+ ```
372
+
373
+ ## Common Patterns
374
+
375
+ ### Contextual Logging
376
+
377
+ ```typescript
378
+ @Injectable()
379
+ export class AuthService {
380
+ constructor(
381
+ @Inject(LoggerService) private logger: LoggerService
382
+ ) {}
383
+
384
+ async login(email: string, password: string) {
385
+ // Add request context
386
+ this.logger.withContext({ email, action: 'login' });
387
+
388
+ this.logger.info('Login attempt');
389
+
390
+ try {
391
+ const user = await this.authenticate(email, password);
392
+ this.logger.info('Login successful', { userId: user.id });
393
+ return user;
394
+ } catch (error) {
395
+ this.logger.error('Login failed', { error });
396
+ throw error;
397
+ } finally {
398
+ // Clean up context
399
+ this.logger.withoutContext(['email', 'action']);
400
+ }
401
+ }
402
+ }
403
+ ```
404
+
405
+ ### Error Logging
406
+
407
+ ```typescript
408
+ @Injectable()
409
+ export class PaymentService {
410
+ constructor(
411
+ @Inject(LoggerService) private logger: LoggerService
412
+ ) {}
413
+
414
+ async processPayment(orderId: string, amount: number) {
415
+ const errorLogger = this.logger.channel('errors');
416
+
417
+ try {
418
+ const result = await this.chargeCard(orderId, amount);
419
+ this.logger.info('Payment processed', { orderId, amount });
420
+ return result;
421
+ } catch (error) {
422
+ errorLogger.error('Payment failed', {
423
+ orderId,
424
+ amount,
425
+ error: error.message,
426
+ stack: error.stack,
427
+ });
428
+ throw error;
429
+ }
430
+ }
431
+ }
432
+ ```
433
+
434
+ ### Audit Logging
435
+
436
+ ```typescript
437
+ @Injectable()
438
+ export class UserService {
439
+ constructor(
440
+ @Inject(LoggerService) private logger: LoggerService
441
+ ) {}
442
+
443
+ async updateUser(userId: string, data: Partial<User>) {
444
+ const auditLogger = this.logger.channel('audit');
445
+
446
+ auditLogger.info('User update started', {
447
+ userId,
448
+ changes: Object.keys(data),
449
+ });
450
+
451
+ const user = await this.db.users.update(userId, data);
452
+
453
+ auditLogger.info('User update completed', {
454
+ userId,
455
+ changes: data,
456
+ });
457
+
458
+ return user;
459
+ }
460
+ }
461
+ ```
462
+
463
+ ### Environment-Based Configuration
464
+
465
+ ```typescript
466
+ import { defineConfig, consolePreset, silentPreset } from '@abdokouta/logger';
467
+
468
+ export const getLoggerConfig = () => {
469
+ const env = process.env.NODE_ENV || 'development';
470
+
471
+ if (env === 'production') {
472
+ return defineConfig({
473
+ default: 'console',
474
+ channels: {
475
+ console: {
476
+ transporters: [new ConsoleTransporter({ level: LogLevel.Warn })],
477
+ },
478
+ errors: {
479
+ transporters: [
480
+ new ConsoleTransporter({ level: LogLevel.Error }),
481
+ new StorageTransporter({ key: 'error-logs' }),
482
+ ],
483
+ },
484
+ },
485
+ });
486
+ }
487
+
488
+ if (env === 'test') {
489
+ return defineConfig(silentPreset);
490
+ }
491
+
492
+ // Development
493
+ return defineConfig({
494
+ ...consolePreset,
495
+ channels: {
496
+ ...consolePreset.channels,
497
+ console: {
498
+ ...consolePreset.channels.console,
499
+ context: { env: 'dev' },
500
+ },
501
+ },
502
+ });
503
+ };
504
+ ```
505
+
506
+ ## Best Practices
507
+
508
+ 1. **Use Appropriate Log Levels**: Debug for development, Info for important events, Warn for issues, Error for failures, Fatal for critical errors
509
+ 2. **Add Context**: Include relevant data to make logs useful
510
+ 3. **Use Channels**: Separate concerns (console, storage, errors, audit)
511
+ 4. **Clean Up Context**: Remove sensitive data after logging
512
+ 5. **Handle Errors Gracefully**: Always catch and log errors
513
+ 6. **Use Structured Logging**: Include structured data in context
514
+ 7. **Monitor Storage**: Set appropriate maxEntries for StorageTransporter
515
+
516
+ ## TypeScript Support
517
+
518
+ Full TypeScript support with comprehensive types:
519
+
520
+ ```typescript
521
+ import type {
522
+ LoggerInterface,
523
+ LoggerServiceInterface,
524
+ LoggerModuleOptions,
525
+ LoggerConfig,
526
+ LogEntry,
527
+ LogLevel,
528
+ TransporterInterface,
529
+ FormatterInterface,
530
+ } from '@abdokouta/logger';
531
+ ```
532
+
533
+ ## Browser Compatibility
534
+
535
+ This package works in all modern browsers that support:
536
+ - localStorage API
537
+ - console API
538
+ - ES2020 features
539
+
540
+ No polyfills required for modern browsers (Chrome 80+, Firefox 75+, Safari 13.1+, Edge 80+).
541
+
542
+ ## License
543
+
544
+ MIT
545
+
546
+ ## Contributing
547
+
548
+ Contributions are welcome! Please read our contributing guidelines before submitting PRs.
549
+
550
+ ## Support
551
+
552
+ - [Documentation](https://refine.dev/docs)
553
+ - [Discord](https://discord.gg/refine)
554
+ - [GitHub Issues](https://github.com/refinedev/refine/issues)
555
+
556
+ ## Related Packages
557
+
558
+ - [@abdokouta/cache](../cache) - Multi-driver cache system
559
+ - [@abdokouta/redis](../redis) - Redis connection management
@@ -0,0 +1,171 @@
1
+ /**
2
+ * Logger Configuration
3
+ *
4
+ * Unified logger configuration following Laravel and NestJS patterns.
5
+ * All logging channels and settings are defined in a single config object.
6
+ *
7
+ * @module config/logger
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * import loggerConfig from '@abdokouta/logger/config/logger.config';
12
+ *
13
+ * LoggerModule.forRoot(loggerConfig);
14
+ * ```
15
+ */
16
+
17
+ import {
18
+ LogLevel,
19
+ SilentTransporter,
20
+ ConsoleTransporter,
21
+ StorageTransporter,
22
+ } from "@abdokouta/logger";
23
+ import type { LoggerModuleOptions } from "@abdokouta/logger";
24
+
25
+ /**
26
+ * Logger configuration
27
+ *
28
+ * Single unified configuration object that automatically adapts to your environment.
29
+ * Uses environment variables for configuration, similar to Laravel's config/logging.php
30
+ *
31
+ * Environment Variables:
32
+ * - LOG_CHANNEL: Default channel (default: 'console')
33
+ * - LOG_LEVEL: Minimum log level (default: 'debug')
34
+ * - APP_NAME: Application name for context (default: 'refine-app')
35
+ * - NODE_ENV: Environment (development/production/test)
36
+ * - LOG_STORAGE_MAX_ENTRIES: Max storage entries (default: 500)
37
+ */
38
+ const loggerConfig: LoggerModuleOptions = {
39
+ /*
40
+ |--------------------------------------------------------------------------
41
+ | Default Log Channel
42
+ |--------------------------------------------------------------------------
43
+ |
44
+ | This option defines the default log channel that will be used to write
45
+ | messages to the logs. The name specified in this option should match
46
+ | one of the channels defined in the "channels" configuration array.
47
+ |
48
+ */
49
+ default: process.env.LOG_CHANNEL || "console",
50
+
51
+ /*
52
+ |--------------------------------------------------------------------------
53
+ | Log Channels
54
+ |--------------------------------------------------------------------------
55
+ |
56
+ | Here you may configure the log channels for your application. Each
57
+ | channel can have multiple transporters for different outputs.
58
+ |
59
+ */
60
+ channels: {
61
+ /**
62
+ * Console Channel
63
+ *
64
+ * Logs to the console/terminal. Good for development.
65
+ */
66
+ console: {
67
+ transporters: [
68
+ new ConsoleTransporter({
69
+ level:
70
+ (process.env.LOG_LEVEL as unknown as LogLevel) || LogLevel.Debug,
71
+ }),
72
+ ],
73
+ context: {
74
+ app: process.env.APP_NAME || "refine-app",
75
+ env: process.env.NODE_ENV || "development",
76
+ },
77
+ },
78
+
79
+ /**
80
+ * Storage Channel
81
+ *
82
+ * Persists logs to storage (localStorage/sessionStorage in browser).
83
+ * Good for debugging and audit trails.
84
+ */
85
+ storage: {
86
+ transporters: [
87
+ new StorageTransporter({
88
+ key: "app-logs",
89
+ maxEntries: Number(process.env.LOG_STORAGE_MAX_ENTRIES) || 500,
90
+ }),
91
+ ],
92
+ context: {
93
+ app: process.env.APP_NAME || "refine-app",
94
+ },
95
+ },
96
+
97
+ /**
98
+ * Combined Channel
99
+ *
100
+ * Logs to both console and storage.
101
+ * Good for production environments.
102
+ */
103
+ combined: {
104
+ transporters: [
105
+ new ConsoleTransporter({
106
+ level: LogLevel.Info,
107
+ }),
108
+ new StorageTransporter({
109
+ key: "app-logs",
110
+ maxEntries: 1000,
111
+ }),
112
+ ],
113
+ context: {
114
+ app: process.env.APP_NAME || "refine-app",
115
+ env: process.env.NODE_ENV || "production",
116
+ },
117
+ },
118
+
119
+ /**
120
+ * Error Channel
121
+ *
122
+ * Only logs errors and critical messages.
123
+ * Useful for error monitoring and alerting.
124
+ */
125
+ errors: {
126
+ transporters: [
127
+ new ConsoleTransporter({
128
+ level: LogLevel.Error,
129
+ }),
130
+ new StorageTransporter({
131
+ key: "error-logs",
132
+ maxEntries: 200,
133
+ }),
134
+ ],
135
+ context: {
136
+ app: process.env.APP_NAME || "refine-app",
137
+ channel: "errors",
138
+ },
139
+ },
140
+
141
+ /**
142
+ * Audit Channel
143
+ *
144
+ * For audit trails and compliance logging.
145
+ * Stores all logs without console output.
146
+ */
147
+ audit: {
148
+ transporters: [
149
+ new StorageTransporter({
150
+ key: "audit-logs",
151
+ maxEntries: 1000,
152
+ }),
153
+ ],
154
+ context: {
155
+ app: process.env.APP_NAME || "refine-app",
156
+ channel: "audit",
157
+ },
158
+ },
159
+
160
+ /**
161
+ * Silent Channel
162
+ *
163
+ * Disables all logging. Useful for testing.
164
+ */
165
+ silent: {
166
+ transporters: [new SilentTransporter()],
167
+ },
168
+ },
169
+ };
170
+
171
+ export default loggerConfig;