0
# @ledgerhq/logs
1
2
@ledgerhq/logs is a unified logging system for all Ledger libraries, providing centralized log dispatching and management across the Ledger Live ecosystem. It offers core logging functionality with the `log()` function for basic logging, a `trace()` function for capturing contextual information, and a `LocalTracer` class for maintaining persistent context across multiple log calls.
3
4
## Package Information
5
6
- **Package Name**: @ledgerhq/logs
7
- **Package Type**: npm
8
- **Language**: TypeScript
9
- **Installation**: `npm install @ledgerhq/logs`
10
11
## Core Imports
12
13
```typescript
14
import { log, trace, listen, LocalTracer, type Log, type TraceContext } from "@ledgerhq/logs";
15
```
16
17
For CommonJS:
18
19
```javascript
20
const { log, trace, listen, LocalTracer } = require("@ledgerhq/logs");
21
```
22
23
## Basic Usage
24
25
```typescript
26
import { log, trace, listen, LocalTracer } from "@ledgerhq/logs";
27
28
// Basic logging
29
log("apdu-in", "Received APDU command", { command: "0x80040000" });
30
31
// Enhanced logging with context
32
trace({
33
type: "hw-connection",
34
message: "Device connected",
35
data: { deviceId: "nano-s-001" },
36
context: { sessionId: "abc123" }
37
});
38
39
// Listen to all log events
40
const unsubscribe = listen((logEntry) => {
41
console.log(`[${logEntry.type}] ${logEntry.message}`, logEntry.data);
42
});
43
44
// Tracer for maintaining context
45
const tracer = new LocalTracer("wallet-sync", { userId: "user123" });
46
tracer.trace("Starting sync", { accountCount: 5 });
47
```
48
49
## Capabilities
50
51
### Basic Logging
52
53
Core logging function for dispatching log events across the system.
54
55
```typescript { .api }
56
/**
57
* Logs something
58
* @param type - A namespaced identifier of the log (not a level like "debug", "error" but more like "apdu-in", "apdu-out", etc...)
59
* @param message - A clear message of the log associated to the type
60
* @param data - Optional data associated to the log event
61
*/
62
function log(type: LogType, message?: string, data?: LogData): void;
63
```
64
65
### Enhanced Tracing
66
67
Advanced logging function that captures more context than the basic log function.
68
69
```typescript { .api }
70
/**
71
* A simple tracer function, only expanding the existing log function
72
* @param params - Object containing trace information
73
*/
74
function trace(params: {
75
type: LogType;
76
message?: string;
77
data?: LogData;
78
context?: TraceContext;
79
}): void;
80
```
81
82
### Event Subscription
83
84
Subscribe to log events with callback functions for processing or forwarding logs.
85
86
```typescript { .api }
87
/**
88
* Adds a subscriber to the emitted logs
89
* @param cb - Callback function called for each future log() with the Log object
90
* @returns Function that can be called to unsubscribe the listener
91
*/
92
function listen(cb: Subscriber): Unsubscribe;
93
```
94
95
### Local Tracer Class
96
97
Class-based tracer for maintaining persistent context across multiple log calls.
98
99
```typescript { .api }
100
/**
101
* A simple tracer class, that can be used to avoid repetition when using the `trace` function
102
*/
103
class LocalTracer {
104
/**
105
* Creates a new LocalTracer instance
106
* @param type - A given type (not level) for the current local tracer ("hw", "withDevice", etc.)
107
* @param context - Anything representing the context where the log occurred
108
*/
109
constructor(type: LogType, context?: TraceContext);
110
111
/**
112
* Trace a message with the tracer's type and context
113
* @param message - Log message
114
* @param data - Optional additional data (Note: signature uses TraceContext but data is passed as LogData to trace function)
115
*/
116
trace(message: string, data?: TraceContext): void;
117
118
/**
119
* Get the current context
120
* @returns Current context or undefined
121
*/
122
getContext(): TraceContext | undefined;
123
124
/**
125
* Set the context (mutates instance)
126
* @param context - New context
127
*/
128
setContext(context?: TraceContext): void;
129
130
/**
131
* Merge additional context (mutates instance)
132
* @param contextToAdd - Context to merge with existing context
133
*/
134
updateContext(contextToAdd: TraceContext): void;
135
136
/**
137
* Get the current log type
138
* @returns Current log type
139
*/
140
getType(): LogType;
141
142
/**
143
* Set the log type (mutates instance)
144
* @param type - New log type
145
*/
146
setType(type: LogType): void;
147
148
/**
149
* Create a new instance with an updated type (immutable)
150
* @param type - New log type
151
* @returns New LocalTracer instance
152
*/
153
withType(type: LogType): LocalTracer;
154
155
/**
156
* Create a new instance with a new context (immutable)
157
* @param context - New context (can be undefined to reset)
158
* @returns New LocalTracer instance
159
*/
160
withContext(context?: TraceContext): LocalTracer;
161
162
/**
163
* Create a new instance with an updated context (immutable)
164
* @param contextToAdd - Context to merge with existing context
165
* @returns New LocalTracer instance
166
*/
167
withUpdatedContext(contextToAdd: TraceContext): LocalTracer;
168
}
169
```
170
171
## Types
172
173
```typescript { .api }
174
/**
175
* Context data structure for tracing system
176
*/
177
type TraceContext = Record<string, unknown>;
178
179
/**
180
* Data associated with log events
181
*/
182
type LogData = any;
183
184
/**
185
* Namespaced identifier for log types
186
*/
187
type LogType = string;
188
189
/**
190
* Core log object structure
191
*/
192
interface Log {
193
/** A namespaced identifier of the log (not a level like "debug", "error" but more like "apdu", "hw", etc...) */
194
type: LogType;
195
/** Optional log message */
196
message?: string;
197
/** Data associated to the log event */
198
data?: LogData;
199
/** Context data, coming for example from the caller's parent, to enable a simple tracing system */
200
context?: TraceContext;
201
/** Unique id among all logs */
202
id: string;
203
/** Date when the log occurred */
204
date: Date;
205
}
206
207
/**
208
* Function to unsubscribe from log events
209
*/
210
type Unsubscribe = () => void;
211
212
/**
213
* Callback function for log event subscribers
214
*/
215
type Subscriber = (log: Log) => void;
216
```
217
218
## Usage Examples
219
220
### Multi-step Process Logging
221
222
```typescript
223
import { LocalTracer } from "@ledgerhq/logs";
224
225
// Create a tracer for a specific operation
226
const syncTracer = new LocalTracer("account-sync", {
227
userId: "user123",
228
sessionId: "session456"
229
});
230
231
// Log start of operation
232
syncTracer.trace("Starting account synchronization");
233
234
// Log progress with additional data
235
syncTracer.trace("Fetching account data", { accountId: "acc789" });
236
237
// Create new tracer for sub-operation
238
const apiTracer = syncTracer.withType("api-call");
239
apiTracer.trace("Calling accounts endpoint", {
240
url: "/api/accounts",
241
method: "GET"
242
});
243
244
// Log completion
245
syncTracer.trace("Account synchronization completed", {
246
duration: 1250,
247
accountsUpdated: 3
248
});
249
```
250
251
### Event Processing Pipeline
252
253
```typescript
254
import { log, listen } from "@ledgerhq/logs";
255
256
// Set up log processing
257
const unsubscribe = listen((logEntry) => {
258
// Forward critical logs to monitoring service
259
if (logEntry.type.includes("error") || logEntry.type.includes("critical")) {
260
sendToMonitoring(logEntry);
261
}
262
263
// Store all logs in local database
264
saveToDatabase(logEntry);
265
266
// Debug output in development
267
if (process.env.NODE_ENV === "development") {
268
console.log(`[${logEntry.date.toISOString()}] ${logEntry.type}: ${logEntry.message}`);
269
}
270
});
271
272
// Emit various log types throughout application
273
log("device-connection", "Hardware wallet connected", { deviceType: "Nano S" });
274
log("transaction-broadcast", "Transaction sent to network", { txHash: "0x..." });
275
log("error-recovery", "Recovered from network error", { attempts: 3 });
276
277
// Clean up when done
278
unsubscribe();
279
```
280
281
### Context Propagation
282
283
```typescript
284
import { LocalTracer } from "@ledgerhq/logs";
285
286
class WalletService {
287
private tracer: LocalTracer;
288
289
constructor(userId: string) {
290
this.tracer = new LocalTracer("wallet-service", { userId });
291
}
292
293
async processTransaction(txData: any) {
294
// Create operation-specific tracer
295
const txTracer = this.tracer.withUpdatedContext({
296
operation: "process-transaction",
297
txId: txData.id
298
});
299
300
txTracer.trace("Starting transaction processing");
301
302
try {
303
// Validation step
304
const validationTracer = txTracer.withType("validation");
305
validationTracer.trace("Validating transaction data");
306
307
// Processing step
308
const processingTracer = txTracer.withType("processing");
309
processingTracer.trace("Processing transaction", { amount: txData.amount });
310
311
txTracer.trace("Transaction processed successfully");
312
} catch (error) {
313
txTracer.trace("Transaction processing failed", { error: error.message });
314
throw error;
315
}
316
}
317
}
318
```
319
320
## Browser Integration
321
322
When used in browser environments, @ledgerhq/logs automatically exposes the `listen` function globally for debugging purposes:
323
324
```javascript
325
// Available in browser console for debugging
326
window.__ledgerLogsListen((log) => {
327
console.log("Debug log:", log);
328
});
329
```