Skip to content

Commit 768e1db

Browse files
authored
Merge pull request #260 from relaystr/copilot/create-custom-modular-logger
Replace logger package with custom WASM-compatible modular logger
2 parents 6c1f4a1 + 7a0190f commit 768e1db

18 files changed

Lines changed: 668 additions & 75 deletions

packages/isar/pubspec.lock

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -329,14 +329,6 @@ packages:
329329
url: "https://pub.dev"
330330
source: hosted
331331
version: "5.1.0"
332-
logger:
333-
dependency: transitive
334-
description:
335-
name: logger
336-
sha256: a7967e31b703831a893bbc3c3dd11db08126fe5f369b5c648a36f821979f5be3
337-
url: "https://pub.dev"
338-
source: hosted
339-
version: "2.6.2"
340332
logging:
341333
dependency: transitive
342334
description:

packages/ndk/example/nwc/get_balance.dart

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,13 @@
33
import 'dart:io';
44

55
import 'package:ndk/ndk.dart';
6-
import 'package:logger/logger.dart' as lib_logger;
76

87
void main() async {
98
// We use an empty bootstrap relay list,
109
// since NWC will provide the relay we connect to so we don't need default relays
1110
final ndk = Ndk.emptyBootstrapRelaysConfig();
1211

13-
Logger.setLogLevel(lib_logger.Level.warning);
12+
Logger.setLogLevel(LogLevel.warning);
1413

1514
// You need an NWC_URI env var or to replace with your NWC uri connection
1615
final nwcUri = Platform.environment['NWC_URI']!;

packages/ndk/example/nwc/get_budget.dart

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,13 @@ import 'dart:io';
44

55
import 'package:ndk/domain_layer/usecases/nwc/responses/get_budget_response.dart';
66
import 'package:ndk/ndk.dart';
7-
import 'package:logger/logger.dart' as lib_logger;
87

98
void main() async {
109
// We use an empty bootstrap relay list,
1110
// since NWC will provide the relay we connect to so we don't need default relays
1211
final ndk = Ndk.emptyBootstrapRelaysConfig();
1312

14-
Logger.setLogLevel(lib_logger.Level.warning);
13+
Logger.setLogLevel(LogLevel.warning);
1514

1615
// You need an NWC_URI env var or to replace with your NWC uri connection
1716
final nwcUri = Platform.environment['NWC_URI']!;
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import 'package:logger/logger.dart' as lib_logger;
1+
import '../shared/logger/log_level.dart';
22

33
/// The default log level for the logger.
4-
const defaultLogLevel = lib_logger.Level.warning;
4+
const defaultLogLevel = LogLevel.warning;

packages/ndk/lib/ndk.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,10 @@ export 'domain_layer/usecases/bunkers/models/nostr_connect.dart';
8888
*/
8989

9090
export 'shared/logger/logger.dart';
91+
export 'shared/logger/log_level.dart';
92+
export 'shared/logger/log_output.dart';
93+
export 'shared/logger/ndk_logger.dart';
94+
export 'shared/logger/console_output.dart';
9195

9296
/**
9397
* event filters

packages/ndk/lib/presentation_layer/ndk_config.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import '../config/request_defaults.dart';
66
import '../domain_layer/entities/event_filter.dart';
77
import '../domain_layer/repositories/cache_manager.dart';
88
import '../domain_layer/repositories/event_verifier.dart';
9-
import 'package:logger/logger.dart' as lib_logger;
9+
import '../shared/logger/log_level.dart';
1010

1111
/// Configuration class for the Nostr Development Kit (NDK)
1212
///
@@ -48,7 +48,7 @@ class NdkConfig {
4848
double defaultBroadcastConsiderDonePercent;
4949

5050
/// log level
51-
lib_logger.Level logLevel;
51+
LogLevel logLevel;
5252

5353
/// User agent string for Http requests and websockets.
5454
String userAgent;
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
# NDK Custom Logger
2+
3+
The NDK now uses a custom, modular logger implementation that is WASM-compatible (no `dart:io` dependency).
4+
5+
## Features
6+
7+
- **WASM Compatible**: No dependency on `dart:io`, making it suitable for web/WASM targets
8+
- **Modular Output System**: Support for multiple log outputs (console, file, network, etc.)
9+
- **Log Levels**: Support for trace, debug, info, warning, error, fatal, all, and off levels
10+
- **Flexible Configuration**: Easy to configure and customize
11+
12+
## Usage
13+
14+
### Basic Usage
15+
16+
The logger is already configured and ready to use:
17+
18+
```dart
19+
import 'package:ndk/ndk.dart';
20+
21+
// Use the static logger instance
22+
Logger.log.d('Debug message');
23+
Logger.log.i('Info message');
24+
Logger.log.w('Warning message');
25+
Logger.log.e('Error message');
26+
```
27+
28+
### Setting Log Level
29+
30+
You can change the log level at runtime:
31+
32+
```dart
33+
// Set to debug level
34+
Logger.setLogLevel(LogLevel.debug);
35+
36+
// Or use the logLevels constants
37+
Logger.setLogLevel(Logger.logLevels.warning);
38+
```
39+
40+
### Available Log Levels
41+
42+
- `LogLevel.all` - Log everything (lowest priority)
43+
- `LogLevel.trace` - Very detailed debugging
44+
- `LogLevel.debug` - Debugging information
45+
- `LogLevel.info` - Informational messages
46+
- `LogLevel.warning` - Warning messages (default)
47+
- `LogLevel.error` - Error messages
48+
- `LogLevel.fatal` - Fatal error messages
49+
- `LogLevel.off` - Disable logging
50+
51+
### Custom Log Outputs
52+
53+
You can create custom log outputs by implementing the `LogOutput` interface:
54+
55+
```dart
56+
import 'package:ndk/ndk.dart';
57+
58+
class MyCustomOutput implements LogOutput {
59+
@override
60+
void output(LogEvent event) {
61+
// Handle the log event
62+
print('Custom: [${event.level.name}] ${event.message}');
63+
}
64+
65+
@override
66+
void destroy() {
67+
// Cleanup when the logger is destroyed
68+
}
69+
}
70+
71+
// Add the custom output to the logger
72+
final customOutput = MyCustomOutput();
73+
Logger.log.addOutput(customOutput);
74+
75+
// Now logs will go to both console and your custom output
76+
Logger.log.i('This goes to multiple outputs');
77+
78+
// Remove when done
79+
Logger.log.removeOutput(customOutput);
80+
```
81+
82+
### Multiple Outputs
83+
84+
The logger supports sending logs to multiple outputs simultaneously:
85+
86+
```dart
87+
// Add multiple outputs
88+
Logger.log.addOutput(fileOutput);
89+
Logger.log.addOutput(networkOutput);
90+
Logger.log.addOutput(customOutput);
91+
92+
// Logs will be sent to console + all added outputs
93+
Logger.log.i('This goes everywhere!');
94+
```
95+
96+
### Custom Logger Instance
97+
98+
You can create custom logger instances for specific components:
99+
100+
```dart
101+
final myLogger = NdkLogger(
102+
level: LogLevel.info,
103+
outputs: [
104+
ConsoleOutput(includeTimestamp: true),
105+
MyCustomOutput(),
106+
],
107+
);
108+
109+
myLogger.i('Message from custom logger');
110+
```
111+
112+
## Configuration via NdkConfig
113+
114+
You can set the log level when initializing NDK:
115+
116+
```dart
117+
final ndk = Ndk(NdkConfig(
118+
cache: MemCacheManager(),
119+
eventVerifier: Bip340EventVerifier(),
120+
logLevel: LogLevel.debug, // Set desired log level
121+
));
122+
```
123+
124+
## Migration from logger package
125+
126+
If you were using the `logger` package directly, update your code:
127+
128+
**Before:**
129+
```dart
130+
import 'package:logger/logger.dart' as lib_logger;
131+
Logger.setLogLevel(lib_logger.Level.warning);
132+
```
133+
134+
**After:**
135+
```dart
136+
import 'package:ndk/ndk.dart';
137+
Logger.setLogLevel(LogLevel.warning);
138+
```
139+
140+
## Example
141+
142+
See [example/logger_example.dart](../../example/logger_example.dart) for a complete example showing:
143+
- Basic usage
144+
- Custom outputs
145+
- Multiple outputs
146+
- Changing log levels
147+
- Custom logger instances
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// coverage:ignore-file
2+
3+
import 'log_event.dart';
4+
import 'log_output.dart';
5+
import 'log_color.dart';
6+
7+
/// Console output with color support
8+
class ConsoleOutput extends LogOutput {
9+
final bool useColors;
10+
final bool showTime;
11+
final bool detailedTime;
12+
13+
ConsoleOutput({
14+
this.useColors = true,
15+
this.showTime = true,
16+
this.detailedTime = false,
17+
});
18+
19+
@override
20+
void output(LogEvent event) {
21+
final levelStr = event.level.name.toUpperCase();
22+
23+
String timestamp = '';
24+
if (showTime) {
25+
if (detailedTime) {
26+
timestamp = '${event.timestamp.toIso8601String()} ';
27+
} else {
28+
final hour = event.timestamp.hour.toString().padLeft(2, '0');
29+
final minute = event.timestamp.minute.toString().padLeft(2, '0');
30+
timestamp = '$hour:$minute ';
31+
}
32+
}
33+
34+
String message;
35+
if (useColors) {
36+
final coloredLevel = LogColor.colorizeLevel(event.level, '[$levelStr]');
37+
message = '$timestamp$coloredLevel ${event.message}';
38+
} else {
39+
message = '$timestamp[$levelStr] ${event.message}';
40+
}
41+
42+
if (event.error != null) {
43+
message += '\nError: ${event.error}';
44+
}
45+
if (event.stackTrace != null) {
46+
message += '\n${event.stackTrace}';
47+
}
48+
49+
print(message);
50+
}
51+
52+
@override
53+
void destroy() {
54+
// Nothing to cleanup for console output
55+
}
56+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// coverage:ignore-file
2+
import 'log_level.dart';
3+
4+
/// ANSI color codes for terminal output
5+
class LogColor {
6+
static const String reset = '\x1B[0m';
7+
static const String black = '\x1B[30m';
8+
static const String red = '\x1B[31m';
9+
static const String green = '\x1B[32m';
10+
static const String yellow = '\x1B[33m';
11+
static const String blue = '\x1B[34m';
12+
static const String magenta = '\x1B[35m';
13+
static const String cyan = '\x1B[36m';
14+
static const String white = '\x1B[37m';
15+
static const String gray = '\x1B[90m';
16+
17+
/// Get color for log level
18+
static String forLevel(LogLevel level) {
19+
switch (level) {
20+
case LogLevel.trace:
21+
return gray;
22+
case LogLevel.debug:
23+
return cyan;
24+
case LogLevel.info:
25+
return green;
26+
case LogLevel.warning:
27+
return yellow;
28+
case LogLevel.error:
29+
return red;
30+
case LogLevel.fatal:
31+
return magenta;
32+
case LogLevel.all:
33+
return blue;
34+
case LogLevel.off:
35+
return reset;
36+
}
37+
}
38+
39+
/// Wrap text with color
40+
static String colorize(String text, String color) {
41+
return '$color$text$reset';
42+
}
43+
44+
/// Colorize message based on log level
45+
static String colorizeLevel(LogLevel level, String text) {
46+
return colorize(text, forLevel(level));
47+
}
48+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import 'log_level.dart';
2+
3+
/// A log event that contains the log level, message, and optional error/stacktrace.
4+
class LogEvent {
5+
/// The log level
6+
final LogLevel level;
7+
8+
/// The log message
9+
final String message;
10+
11+
/// Optional error object
12+
final Object? error;
13+
14+
/// Optional stack trace
15+
final StackTrace? stackTrace;
16+
17+
/// Timestamp when the log was created
18+
final DateTime timestamp;
19+
20+
/// Constructor
21+
LogEvent({
22+
required this.level,
23+
required this.message,
24+
this.error,
25+
this.stackTrace,
26+
}) : timestamp = DateTime.now();
27+
}

0 commit comments

Comments
 (0)