Skip to content

Commit fb8a6f1

Browse files
authored
feat: add component logger (#2198)
Adds a `ComponentLogger` to `@libp2p/logger` with implementations that prefixes all log messages with a truncated peer id or an arbitrary string. When running multiple libp2p instances simultaneously it's often hard to work out which log messages come from which instance. This will solve this problem. Refs #2105
1 parent 4f2a41d commit fb8a6f1

22 files changed

+407
-229
lines changed

packages/interface/src/index.ts

+26
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,23 @@ export interface IdentifyResult {
106106
connection: Connection
107107
}
108108

109+
/**
110+
* Logger component for libp2p
111+
*/
112+
export interface Logger {
113+
(formatter: any, ...args: any[]): void
114+
error(formatter: any, ...args: any[]): void
115+
trace(formatter: any, ...args: any[]): void
116+
enabled: boolean
117+
}
118+
119+
/**
120+
* Peer logger component for libp2p
121+
*/
122+
export interface ComponentLogger {
123+
forComponent(name: string): Logger
124+
}
125+
109126
/**
110127
* Once you have a libp2p instance, you can listen to several events it emits,
111128
* so that you can be notified of relevant network events.
@@ -408,6 +425,8 @@ export interface Libp2p<T extends ServiceMap = ServiceMap> extends Startable, Ty
408425
*/
409426
metrics?: Metrics
410427

428+
logger: ComponentLogger
429+
411430
/**
412431
* Get a deduplicated list of peer advertising multiaddrs by concatenating
413432
* the listen addresses used by transports with any configured
@@ -626,6 +645,13 @@ export interface AbortOptions {
626645
signal?: AbortSignal
627646
}
628647

648+
/**
649+
* An object that contains a Logger as the `log` property.
650+
*/
651+
export interface LoggerOptions {
652+
log: Logger
653+
}
654+
629655
/**
630656
* Returns a new type with all fields marked optional.
631657
*

packages/libp2p/src/components.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { CodeError } from '@libp2p/interface/errors'
22
import { isStartable, type Startable } from '@libp2p/interface/startable'
3-
import type { Libp2pEvents } from '@libp2p/interface'
3+
import { defaultLogger } from '@libp2p/logger'
4+
import type { Libp2pEvents, ComponentLogger } from '@libp2p/interface'
45
import type { ConnectionProtector } from '@libp2p/interface/connection'
56
import type { ConnectionGater } from '@libp2p/interface/connection-gater'
67
import type { ContentRouting } from '@libp2p/interface/content-routing'
@@ -18,6 +19,7 @@ import type { Datastore } from 'interface-datastore'
1819

1920
export interface Components extends Record<string, any>, Startable {
2021
peerId: PeerId
22+
logger: ComponentLogger
2123
events: TypedEventTarget<Libp2pEvents>
2224
addressManager: AddressManager
2325
peerStore: PeerStore
@@ -35,6 +37,7 @@ export interface Components extends Record<string, any>, Startable {
3537

3638
export interface ComponentsInit {
3739
peerId?: PeerId
40+
logger?: ComponentLogger
3841
events?: TypedEventTarget<Libp2pEvents>
3942
addressManager?: AddressManager
4043
peerStore?: PeerStore
@@ -60,6 +63,10 @@ class DefaultComponents implements Startable {
6063
for (const [key, value] of Object.entries(init)) {
6164
this.components[key] = value
6265
}
66+
67+
if (this.components.logger == null) {
68+
this.components.logger = defaultLogger()
69+
}
6370
}
6471

6572
isStarted (): boolean {

packages/libp2p/src/connection-manager/auto-dial.ts

+22-22
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
1-
import { logger } from '@libp2p/logger'
21
import { PeerMap, PeerSet } from '@libp2p/peer-collections'
32
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
43
import { PeerJobQueue } from '../utils/peer-job-queue.js'
54
import { AUTO_DIAL_CONCURRENCY, AUTO_DIAL_DISCOVERED_PEERS_DEBOUNCE, AUTO_DIAL_INTERVAL, AUTO_DIAL_MAX_QUEUE_LENGTH, AUTO_DIAL_PEER_RETRY_THRESHOLD, AUTO_DIAL_PRIORITY, LAST_DIAL_FAILURE_KEY, MIN_CONNECTIONS } from './constants.js'
6-
import type { Libp2pEvents } from '@libp2p/interface'
5+
import type { Libp2pEvents, Logger, ComponentLogger } from '@libp2p/interface'
76
import type { TypedEventTarget } from '@libp2p/interface/events'
87
import type { PeerStore } from '@libp2p/interface/peer-store'
98
import type { Startable } from '@libp2p/interface/startable'
109
import type { ConnectionManager } from '@libp2p/interface-internal/connection-manager'
1110

12-
const log = logger('libp2p:connection-manager:auto-dial')
13-
1411
interface AutoDialInit {
1512
minConnections?: number
1613
maxQueueLength?: number
@@ -25,6 +22,7 @@ interface AutoDialComponents {
2522
connectionManager: ConnectionManager
2623
peerStore: PeerStore
2724
events: TypedEventTarget<Libp2pEvents>
25+
logger: ComponentLogger
2826
}
2927

3028
const defaultOptions = {
@@ -50,6 +48,7 @@ export class AutoDial implements Startable {
5048
private autoDialInterval?: ReturnType<typeof setInterval>
5149
private started: boolean
5250
private running: boolean
51+
readonly #log: Logger
5352

5453
/**
5554
* Proactively tries to connect to known peers stored in the PeerStore.
@@ -65,20 +64,21 @@ export class AutoDial implements Startable {
6564
this.autoDialMaxQueueLength = init.maxQueueLength ?? defaultOptions.maxQueueLength
6665
this.autoDialPeerRetryThresholdMs = init.autoDialPeerRetryThreshold ?? defaultOptions.autoDialPeerRetryThreshold
6766
this.autoDialDiscoveredPeersDebounce = init.autoDialDiscoveredPeersDebounce ?? defaultOptions.autoDialDiscoveredPeersDebounce
67+
this.#log = components.logger.forComponent('libp2p:connection-manager:auto-dial')
6868
this.started = false
6969
this.running = false
7070
this.queue = new PeerJobQueue({
7171
concurrency: init.autoDialConcurrency ?? defaultOptions.autoDialConcurrency
7272
})
7373
this.queue.addListener('error', (err) => {
74-
log.error('error during auto-dial', err)
74+
this.#log.error('error during auto-dial', err)
7575
})
7676

7777
// check the min connection limit whenever a peer disconnects
7878
components.events.addEventListener('connection:close', () => {
7979
this.autoDial()
8080
.catch(err => {
81-
log.error(err)
81+
this.#log.error(err)
8282
})
8383
})
8484

@@ -93,7 +93,7 @@ export class AutoDial implements Startable {
9393
debounce = setTimeout(() => {
9494
this.autoDial()
9595
.catch(err => {
96-
log.error(err)
96+
this.#log.error(err)
9797
})
9898
}, this.autoDialDiscoveredPeersDebounce)
9999
})
@@ -107,7 +107,7 @@ export class AutoDial implements Startable {
107107
this.autoDialInterval = setTimeout(() => {
108108
this.autoDial()
109109
.catch(err => {
110-
log.error('error while autodialing', err)
110+
this.#log.error('error while autodialing', err)
111111
})
112112
}, this.autoDialIntervalMs)
113113
this.started = true
@@ -116,7 +116,7 @@ export class AutoDial implements Startable {
116116
afterStart (): void {
117117
this.autoDial()
118118
.catch(err => {
119-
log.error('error while autodialing', err)
119+
this.#log.error('error while autodialing', err)
120120
})
121121
}
122122

@@ -139,24 +139,24 @@ export class AutoDial implements Startable {
139139
// Already has enough connections
140140
if (numConnections >= this.minConnections) {
141141
if (this.minConnections > 0) {
142-
log.trace('have enough connections %d/%d', numConnections, this.minConnections)
142+
this.#log.trace('have enough connections %d/%d', numConnections, this.minConnections)
143143
}
144144
return
145145
}
146146

147147
if (this.queue.size > this.autoDialMaxQueueLength) {
148-
log('not enough connections %d/%d but auto dial queue is full', numConnections, this.minConnections)
148+
this.#log('not enough connections %d/%d but auto dial queue is full', numConnections, this.minConnections)
149149
return
150150
}
151151

152152
if (this.running) {
153-
log('not enough connections %d/%d - but skipping autodial as it is already running', numConnections, this.minConnections)
153+
this.#log('not enough connections %d/%d - but skipping autodial as it is already running', numConnections, this.minConnections)
154154
return
155155
}
156156

157157
this.running = true
158158

159-
log('not enough connections %d/%d - will dial peers to increase the number of connections', numConnections, this.minConnections)
159+
this.#log('not enough connections %d/%d - will dial peers to increase the number of connections', numConnections, this.minConnections)
160160

161161
const dialQueue = new PeerSet(
162162
// @ts-expect-error boolean filter removes falsy peer IDs
@@ -172,25 +172,25 @@ export class AutoDial implements Startable {
172172
(peer) => {
173173
// Remove peers without addresses
174174
if (peer.addresses.length === 0) {
175-
log.trace('not autodialing %p because they have no addresses', peer.id)
175+
this.#log.trace('not autodialing %p because they have no addresses', peer.id)
176176
return false
177177
}
178178

179179
// remove peers we are already connected to
180180
if (connections.has(peer.id)) {
181-
log.trace('not autodialing %p because they are already connected', peer.id)
181+
this.#log.trace('not autodialing %p because they are already connected', peer.id)
182182
return false
183183
}
184184

185185
// remove peers we are already dialling
186186
if (dialQueue.has(peer.id)) {
187-
log.trace('not autodialing %p because they are already being dialed', peer.id)
187+
this.#log.trace('not autodialing %p because they are already being dialed', peer.id)
188188
return false
189189
}
190190

191191
// remove peers already in the autodial queue
192192
if (this.queue.hasJob(peer.id)) {
193-
log.trace('not autodialing %p because they are already being autodialed', peer.id)
193+
this.#log.trace('not autodialing %p because they are already being autodialed', peer.id)
194194
return false
195195
}
196196

@@ -249,27 +249,27 @@ export class AutoDial implements Startable {
249249
return Date.now() - lastDialFailureTimestamp > this.autoDialPeerRetryThresholdMs
250250
})
251251

252-
log('selected %d/%d peers to dial', peersThatHaveNotFailed.length, peers.length)
252+
this.#log('selected %d/%d peers to dial', peersThatHaveNotFailed.length, peers.length)
253253

254254
for (const peer of peersThatHaveNotFailed) {
255255
this.queue.add(async () => {
256256
const numConnections = this.connectionManager.getConnectionsMap().size
257257

258258
// Check to see if we still need to auto dial
259259
if (numConnections >= this.minConnections) {
260-
log('got enough connections now %d/%d', numConnections, this.minConnections)
260+
this.#log('got enough connections now %d/%d', numConnections, this.minConnections)
261261
this.queue.clear()
262262
return
263263
}
264264

265-
log('connecting to a peerStore stored peer %p', peer.id)
265+
this.#log('connecting to a peerStore stored peer %p', peer.id)
266266
await this.connectionManager.openConnection(peer.id, {
267267
priority: this.autoDialPriority
268268
})
269269
}, {
270270
peerId: peer.id
271271
}).catch(err => {
272-
log.error('could not connect to peerStore stored peer', err)
272+
this.#log.error('could not connect to peerStore stored peer', err)
273273
})
274274
}
275275

@@ -279,7 +279,7 @@ export class AutoDial implements Startable {
279279
this.autoDialInterval = setTimeout(() => {
280280
this.autoDial()
281281
.catch(err => {
282-
log.error('error while autodialing', err)
282+
this.#log.error('error while autodialing', err)
283283
})
284284
}, this.autoDialIntervalMs)
285285
}

packages/libp2p/src/connection-manager/connection-pruner.ts

+10-10
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
1-
import { logger } from '@libp2p/logger'
21
import { PeerMap } from '@libp2p/peer-collections'
32
import { MAX_CONNECTIONS } from './constants.js'
4-
import type { Libp2pEvents } from '@libp2p/interface'
3+
import type { Libp2pEvents, Logger, ComponentLogger } from '@libp2p/interface'
54
import type { TypedEventTarget } from '@libp2p/interface/events'
65
import type { PeerStore } from '@libp2p/interface/peer-store'
76
import type { ConnectionManager } from '@libp2p/interface-internal/connection-manager'
87
import type { Multiaddr } from '@multiformats/multiaddr'
98

10-
const log = logger('libp2p:connection-manager:connection-pruner')
11-
129
interface ConnectionPrunerInit {
1310
maxConnections?: number
1411
allow?: Multiaddr[]
@@ -18,6 +15,7 @@ interface ConnectionPrunerComponents {
1815
connectionManager: ConnectionManager
1916
peerStore: PeerStore
2017
events: TypedEventTarget<Libp2pEvents>
18+
logger: ComponentLogger
2119
}
2220

2321
const defaultOptions = {
@@ -34,19 +32,21 @@ export class ConnectionPruner {
3432
private readonly peerStore: PeerStore
3533
private readonly allow: Multiaddr[]
3634
private readonly events: TypedEventTarget<Libp2pEvents>
35+
readonly #log: Logger
3736

3837
constructor (components: ConnectionPrunerComponents, init: ConnectionPrunerInit = {}) {
3938
this.maxConnections = init.maxConnections ?? defaultOptions.maxConnections
4039
this.allow = init.allow ?? defaultOptions.allow
4140
this.connectionManager = components.connectionManager
4241
this.peerStore = components.peerStore
4342
this.events = components.events
43+
this.#log = components.logger.forComponent('libp2p:connection-manager:connection-pruner')
4444

4545
// check the max connection limit whenever a peer connects
4646
components.events.addEventListener('connection:open', () => {
4747
this.maybePruneConnections()
4848
.catch(err => {
49-
log.error(err)
49+
this.#log.error(err)
5050
})
5151
})
5252
}
@@ -60,12 +60,12 @@ export class ConnectionPruner {
6060
const numConnections = connections.length
6161
const toPrune = Math.max(numConnections - this.maxConnections, 0)
6262

63-
log('checking max connections limit %d/%d', numConnections, this.maxConnections)
63+
this.#log('checking max connections limit %d/%d', numConnections, this.maxConnections)
6464
if (numConnections <= this.maxConnections) {
6565
return
6666
}
6767

68-
log('max connections limit exceeded %d/%d, pruning %d connection(s)', numConnections, this.maxConnections, toPrune)
68+
this.#log('max connections limit exceeded %d/%d, pruning %d connection(s)', numConnections, this.maxConnections, toPrune)
6969
const peerValues = new PeerMap<number>()
7070

7171
// work out peer values
@@ -87,7 +87,7 @@ export class ConnectionPruner {
8787
}, 0))
8888
} catch (err: any) {
8989
if (err.code !== 'ERR_NOT_FOUND') {
90-
log.error('error loading peer tags', err)
90+
this.#log.error('error loading peer tags', err)
9191
}
9292
}
9393
}
@@ -124,7 +124,7 @@ export class ConnectionPruner {
124124
const toClose = []
125125

126126
for (const connection of sortedConnections) {
127-
log('too many connections open - closing a connection to %p', connection.remotePeer)
127+
this.#log('too many connections open - closing a connection to %p', connection.remotePeer)
128128
// check allow list
129129
const connectionInAllowList = this.allow.some((ma) => {
130130
return connection.remoteAddr.toString().startsWith(ma.toString())
@@ -146,7 +146,7 @@ export class ConnectionPruner {
146146
try {
147147
await connection.close()
148148
} catch (err) {
149-
log.error(err)
149+
this.#log.error(err)
150150
}
151151
})
152152
)

0 commit comments

Comments
 (0)