From f5176d5cadcc7e87f8bc01389b2101d03529c207 Mon Sep 17 00:00:00 2001 From: Mohammad Kermani Date: Thu, 16 May 2024 08:37:11 +0000 Subject: [PATCH 1/2] feat(utils): add libp2pLoggerFactory for customizing libp2p logger --- .changeset/grumpy-bikes-grow.md | 5 ++ package-lock.json | 121 +++++++++++++++++----------- packages/utils/lib/index.ts | 1 + packages/utils/lib/logger/format.ts | 57 +++++++++++++ packages/utils/lib/logger/index.ts | 50 ++++++++++++ packages/utils/package.json | 5 +- 6 files changed, 189 insertions(+), 50 deletions(-) create mode 100644 .changeset/grumpy-bikes-grow.md create mode 100644 packages/utils/lib/logger/format.ts create mode 100644 packages/utils/lib/logger/index.ts diff --git a/.changeset/grumpy-bikes-grow.md b/.changeset/grumpy-bikes-grow.md new file mode 100644 index 0000000..7bab5c9 --- /dev/null +++ b/.changeset/grumpy-bikes-grow.md @@ -0,0 +1,5 @@ +--- +'@rosen-bridge/rosenet-utils': minor +--- + +add libp2pLoggerFactory for customizing libp2p logger diff --git a/package-lock.json b/package-lock.json index 9b95ecf..adc4201 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1868,14 +1868,14 @@ } }, "node_modules/@libp2p/interface": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@libp2p/interface/-/interface-1.1.3.tgz", - "integrity": "sha512-id22Ve5acg6CM0jjL8s9cyEaBYWn7z1R+1gy75RpHi0qgW15ifozwi0oFSTGLVA5XzRnNzioDLj+ZP6QwvhIVQ==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@libp2p/interface/-/interface-1.3.1.tgz", + "integrity": "sha512-KJoYP6biAgIHUU3pxaixaaYCvIHZshzXetxfoNigadAZ3hCGuwpdFhk7IABEaI3RgadOOYUwW3MXPbL+cxnXVQ==", "dependencies": { - "@multiformats/multiaddr": "^12.1.14", + "@multiformats/multiaddr": "^12.2.1", "it-pushable": "^3.2.3", "it-stream-types": "^2.0.1", - "multiformats": "^13.0.1", + "multiformats": "^13.1.0", "progress-events": "^1.0.0", "uint8arraylist": "^2.4.8" } @@ -1891,6 +1891,46 @@ "uint8arraylist": "^2.4.8" } }, + "node_modules/@libp2p/interface/node_modules/@multiformats/multiaddr": { + "version": "12.2.1", + "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.2.1.tgz", + "integrity": "sha512-UwjoArBbv64FlaetV4DDwh+PUMfzXUBltxQwdh+uTYnGFzVa8ZfJsn1vt1RJlJ6+Xtrm3RMekF/B+K338i2L5Q==", + "dependencies": { + "@chainsafe/is-ip": "^2.0.1", + "@chainsafe/netmask": "^2.0.0", + "@libp2p/interface": "^1.0.0", + "@multiformats/dns": "^1.0.3", + "multiformats": "^13.0.0", + "uint8-varint": "^2.0.1", + "uint8arrays": "^5.0.0" + } + }, + "node_modules/@libp2p/logger": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/@libp2p/logger/-/logger-4.0.12.tgz", + "integrity": "sha512-eSiHY06Zijq6b1rMBob/ZuGBEavFm8IPNPEzeOU3JrBU7v/OV8Da0FesbemtkudZVPRi8mqRoOiIwmWn0mObng==", + "dependencies": { + "@libp2p/interface": "^1.3.1", + "@multiformats/multiaddr": "^12.2.1", + "debug": "^4.3.4", + "interface-datastore": "^8.2.11", + "multiformats": "^13.1.0" + } + }, + "node_modules/@libp2p/logger/node_modules/@multiformats/multiaddr": { + "version": "12.2.1", + "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.2.1.tgz", + "integrity": "sha512-UwjoArBbv64FlaetV4DDwh+PUMfzXUBltxQwdh+uTYnGFzVa8ZfJsn1vt1RJlJ6+Xtrm3RMekF/B+K338i2L5Q==", + "dependencies": { + "@chainsafe/is-ip": "^2.0.1", + "@chainsafe/netmask": "^2.0.0", + "@libp2p/interface": "^1.0.0", + "@multiformats/dns": "^1.0.3", + "multiformats": "^13.0.0", + "uint8-varint": "^2.0.1", + "uint8arrays": "^5.0.0" + } + }, "node_modules/@libp2p/mplex": { "version": "10.0.15", "resolved": "https://registry.npmjs.org/@libp2p/mplex/-/mplex-10.0.15.tgz", @@ -2102,18 +2142,6 @@ "uint8arraylist": "^2.4.8" } }, - "node_modules/@libp2p/utils/node_modules/@libp2p/logger": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@libp2p/logger/-/logger-4.0.6.tgz", - "integrity": "sha512-ofTE3kDivBJnUSoX68nOeg1EuAnIE8oUjUnQnuKrxH+nh0JtjTcvwwIzjmm4nApwb4xj2dgPSDvU38Mjmu3TvA==", - "dependencies": { - "@libp2p/interface": "^1.1.3", - "@multiformats/multiaddr": "^12.1.14", - "debug": "^4.3.4", - "interface-datastore": "^8.2.10", - "multiformats": "^13.0.1" - } - }, "node_modules/@manypkg/find-root": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@manypkg/find-root/-/find-root-1.1.0.tgz", @@ -3759,18 +3787,6 @@ "uint8arrays": "^5.0.0" } }, - "node_modules/datastore-core/node_modules/@libp2p/logger": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@libp2p/logger/-/logger-4.0.6.tgz", - "integrity": "sha512-ofTE3kDivBJnUSoX68nOeg1EuAnIE8oUjUnQnuKrxH+nh0JtjTcvwwIzjmm4nApwb4xj2dgPSDvU38Mjmu3TvA==", - "dependencies": { - "@libp2p/interface": "^1.1.3", - "@multiformats/multiaddr": "^12.1.14", - "debug": "^4.3.4", - "interface-datastore": "^8.2.10", - "multiformats": "^13.0.1" - } - }, "node_modules/datastore-core/node_modules/it-all": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/it-all/-/it-all-3.0.4.tgz", @@ -5178,12 +5194,12 @@ "license": "ISC" }, "node_modules/interface-datastore": { - "version": "8.2.10", - "resolved": "https://registry.npmjs.org/interface-datastore/-/interface-datastore-8.2.10.tgz", - "integrity": "sha512-D8RuxMdjOPB+j6WMDJ+I2aXTDzUT6DIVjgzo1E+ODL7w8WrSFl9FXD2SYmgj6vVzdb7Kb5qmAI9pEnDZJz7ifg==", + "version": "8.2.11", + "resolved": "https://registry.npmjs.org/interface-datastore/-/interface-datastore-8.2.11.tgz", + "integrity": "sha512-9E0iXehfp/j0UbZ2mvlYB4K9pP7uQBCppfuy8WHs1EHF6wLQrM9+zwyX+8Qt6HnH4GKZRyXX/CNXm6oD4+QYgA==", "dependencies": { "interface-store": "^5.0.0", - "uint8arrays": "^5.0.0" + "uint8arrays": "^5.0.2" } }, "node_modules/interface-store": { @@ -5922,18 +5938,6 @@ "uint8arrays": "^5.0.1" } }, - "node_modules/libp2p/node_modules/@libp2p/logger": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@libp2p/logger/-/logger-4.0.6.tgz", - "integrity": "sha512-ofTE3kDivBJnUSoX68nOeg1EuAnIE8oUjUnQnuKrxH+nh0JtjTcvwwIzjmm4nApwb4xj2dgPSDvU38Mjmu3TvA==", - "dependencies": { - "@libp2p/interface": "^1.1.3", - "@multiformats/multiaddr": "^12.1.14", - "debug": "^4.3.4", - "interface-datastore": "^8.2.10", - "multiformats": "^13.0.1" - } - }, "node_modules/libp2p/node_modules/it-merge": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/it-merge/-/it-merge-3.0.3.tgz", @@ -6552,9 +6556,9 @@ "license": "MIT" }, "node_modules/multiformats": { - "version": "13.0.1", - "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-13.0.1.tgz", - "integrity": "sha512-bt3R5iXe2O8xpp3wkmQhC73b/lC4S2ihU8Dndwcsysqbydqb8N+bpP116qMcClZ17g58iSIwtXUTcg2zT4sniA==" + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-13.1.0.tgz", + "integrity": "sha512-HzdtdBwxsIkzpeXzhQ5mAhhuxcHbjEHH+JQoxt7hG/2HGFjjwyolLo7hbaexcnhoEuV4e0TNJ8kkpMjiEYY4VQ==" }, "node_modules/nanoid": { "version": "3.3.7", @@ -9918,9 +9922,11 @@ "@libp2p/crypto": "^4.0.2", "@libp2p/peer-id-factory": "^4.0.6", "@rosen-bridge/logger-interface": "^0.2.0", - "libp2p": "^1.2.3" + "libp2p": "^1.2.3", + "multiformats": "^13.1.0" }, "devDependencies": { + "@multiformats/multiaddr": "^12.2.1", "@types/node": "^20.11.9", "@typescript-eslint/eslint-plugin": "^6.19.1", "@typescript-eslint/parser": "^6.19.1", @@ -9928,6 +9934,7 @@ "eslint": "^8.56.0", "eslint-config-prettier": "^9.1.0", "extensionless": "^1.9.6", + "interface-datastore": "^8.2.11", "prettier": "^3.2.4", "typescript": "^5.3.3", "vitest": "^1.2.2" @@ -9936,6 +9943,21 @@ "node": ">=20.11.0" } }, + "packages/utils/node_modules/@multiformats/multiaddr": { + "version": "12.2.1", + "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.2.1.tgz", + "integrity": "sha512-UwjoArBbv64FlaetV4DDwh+PUMfzXUBltxQwdh+uTYnGFzVa8ZfJsn1vt1RJlJ6+Xtrm3RMekF/B+K338i2L5Q==", + "dev": true, + "dependencies": { + "@chainsafe/is-ip": "^2.0.1", + "@chainsafe/netmask": "^2.0.0", + "@libp2p/interface": "^1.0.0", + "@multiformats/dns": "^1.0.3", + "multiformats": "^13.0.0", + "uint8-varint": "^2.0.1", + "uint8arrays": "^5.0.0" + } + }, "services-legacy/relay": { "version": "0.1.0", "extraneous": true, @@ -10060,6 +10082,7 @@ } }, "tests/scaling-pubsub": { + "name": "@rosenet-tests/scaling-pubsub", "version": "0.0.0", "license": "GPL-3.0", "dependencies": { diff --git a/packages/utils/lib/index.ts b/packages/utils/lib/index.ts index 7043256..4baa595 100644 --- a/packages/utils/lib/index.ts +++ b/packages/utils/lib/index.ts @@ -1,2 +1,3 @@ export { default as addEventListeners } from './addEventListeners'; export { default as privateKeyToPeerId } from './privateKeyToPeerId'; +export { default as libp2pLoggerFactory } from './logger'; diff --git a/packages/utils/lib/logger/format.ts b/packages/utils/lib/logger/format.ts new file mode 100644 index 0000000..f113116 --- /dev/null +++ b/packages/utils/lib/logger/format.ts @@ -0,0 +1,57 @@ +import { format as utilFormat } from 'node:util'; + +import { PeerId } from '@libp2p/interface'; +import { Multiaddr } from '@multiformats/multiaddr'; +import { Key } from 'interface-datastore'; +import { base32 } from 'multiformats/bases/base32'; +import { base58btc } from 'multiformats/bases/base58'; +import { base64 } from 'multiformats/bases/base64'; +import { CID } from 'multiformats/cid'; + +// based on https://github.com/libp2p/js-libp2p/blob/3c73707ff5c1635d4ab26dcc39499ab497d217a6/packages/logger/src/index.ts#L45 +const formatters = { + b: (v?: Uint8Array) => { + return v == null ? 'undefined' : base58btc.baseEncode(v); + }, + t: (v?: Uint8Array) => { + return v == null ? 'undefined' : base32.baseEncode(v); + }, + m: (v?: Uint8Array) => { + return v == null ? 'undefined' : base64.baseEncode(v); + }, + p: (v?: PeerId) => { + return v == null ? 'undefined' : v.toString(); + }, + c: (v?: CID) => { + return v == null ? 'undefined' : v.toString(); + }, + k: (v: Key) => { + return v == null ? 'undefined' : v.toString(); + }, + a: (v?: Multiaddr) => { + return v == null ? 'undefined' : v.toString(); + }, +}; + +/** + * format a string like `util.format`, but support custom libp2p specifiers, too + * based on https://github.com/segmentio/fmt + * @param str + * @param args + */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const format = (str: string, ...args: any[]) => { + let j = 0; + + return str.replace(/%([a-z])/gi, (match, f: keyof typeof formatters) => { + if (formatters[f]) { + return formatters[f](args[j++]); + } + if (f) { + return utilFormat(`%${f}`, args[j++]); + } + return match; + }); +}; + +export default format; diff --git a/packages/utils/lib/logger/index.ts b/packages/utils/lib/logger/index.ts new file mode 100644 index 0000000..3afd127 --- /dev/null +++ b/packages/utils/lib/logger/index.ts @@ -0,0 +1,50 @@ +import { ComponentLogger, Logger } from '@libp2p/interface'; +import { AbstractLogger, DummyLogger } from '@rosen-bridge/logger-interface'; + +import format from './format'; + +/** + * convert AbstractLogger to a printf-friendly logger + * @param name + * @param logger + * @param level + */ +const convertToPrintfFormat = + (name: string, logger: AbstractLogger, level: 'info' | 'error' | 'debug') => + (formatter: string, ...rest: unknown[]) => { + const formatted = format(formatter, ...rest); + logger[level](`[${name}] ${formatted}`); + }; + +/** + * create logger for a specific libp2p component + * @param name + * @param logger + */ +const createLogger = (name: string, logger: AbstractLogger): Logger => { + const componentLogger = convertToPrintfFormat(name, logger, 'info') as Logger; + componentLogger.trace = convertToPrintfFormat(name, logger, 'debug'); + componentLogger.error = convertToPrintfFormat(name, logger, 'error'); + componentLogger.enabled = true; + + return componentLogger; +}; + +/** + * create a ComponentLogger to be used as alternative to default libp2p logger + * @param logger + * @param components + */ +const libp2pLoggerFactory: ( + logger: AbstractLogger, + components: string[], +) => ComponentLogger = (logger: AbstractLogger, components: string[]) => ({ + forComponent(name: string) { + if (components.includes(name) || components.includes('*')) { + return createLogger(name, logger); + } + return createLogger('', new DummyLogger()); + }, +}); + +export default libp2pLoggerFactory; diff --git a/packages/utils/package.json b/packages/utils/package.json index 21bb089..97a0815 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -18,6 +18,7 @@ "type-check": "tsc --noEmit" }, "devDependencies": { + "@multiformats/multiaddr": "^12.2.1", "@types/node": "^20.11.9", "@typescript-eslint/eslint-plugin": "^6.19.1", "@typescript-eslint/parser": "^6.19.1", @@ -25,6 +26,7 @@ "eslint": "^8.56.0", "eslint-config-prettier": "^9.1.0", "extensionless": "^1.9.6", + "interface-datastore": "^8.2.11", "prettier": "^3.2.4", "typescript": "^5.3.3", "vitest": "^1.2.2" @@ -36,6 +38,7 @@ "@libp2p/crypto": "^4.0.2", "@libp2p/peer-id-factory": "^4.0.6", "@rosen-bridge/logger-interface": "^0.2.0", - "libp2p": "^1.2.3" + "libp2p": "^1.2.3", + "multiformats": "^13.1.0" } } From 5499c316901f7d9beab2c078e1e6b5a4bb955551 Mon Sep 17 00:00:00 2001 From: Mohammad Kermani Date: Thu, 16 May 2024 09:22:58 +0000 Subject: [PATCH 2/2] feat(rosenet-node, rosenet-relay): add config to enable libp2p logs --- .changeset/quiet-kings-raise.md | 6 ++++++ packages/rosenet-node/lib/createRoseNetNode.ts | 2 ++ packages/rosenet-node/lib/types.ts | 3 +++ packages/rosenet-relay/lib/createRoseNetRelay.ts | 2 ++ packages/rosenet-relay/lib/types.ts | 3 +++ 5 files changed, 16 insertions(+) create mode 100644 .changeset/quiet-kings-raise.md diff --git a/.changeset/quiet-kings-raise.md b/.changeset/quiet-kings-raise.md new file mode 100644 index 0000000..f81a654 --- /dev/null +++ b/.changeset/quiet-kings-raise.md @@ -0,0 +1,6 @@ +--- +'@rosen-bridge/rosenet-relay': minor +'@rosen-bridge/rosenet-node': minor +--- + +add config to enable libp2p logs diff --git a/packages/rosenet-node/lib/createRoseNetNode.ts b/packages/rosenet-node/lib/createRoseNetNode.ts index 83e7b6a..458059d 100644 --- a/packages/rosenet-node/lib/createRoseNetNode.ts +++ b/packages/rosenet-node/lib/createRoseNetNode.ts @@ -13,6 +13,7 @@ import { createLibp2p } from 'libp2p'; import { addEventListeners, + libp2pLoggerFactory, privateKeyToPeerId, } from '@rosen-bridge/rosenet-utils'; @@ -112,6 +113,7 @@ const createRoseNetNode = async ({ runOnTransientConnection: true, }), }, + logger: libp2pLoggerFactory(logger, config.debug?.libp2pComponents ?? []), }); RoseNetNodeContext.logger.debug('RoseNet node created'); diff --git a/packages/rosenet-node/lib/types.ts b/packages/rosenet-node/lib/types.ts index 5de3b84..51e5488 100644 --- a/packages/rosenet-node/lib/types.ts +++ b/packages/rosenet-node/lib/types.ts @@ -6,4 +6,7 @@ export interface RoseNetNodeConfig { privateKey: string; port?: number; whitelist?: string[]; + debug?: { + libp2pComponents?: string[]; + }; } diff --git a/packages/rosenet-relay/lib/createRoseNetRelay.ts b/packages/rosenet-relay/lib/createRoseNetRelay.ts index a7b10bb..031b33b 100644 --- a/packages/rosenet-relay/lib/createRoseNetRelay.ts +++ b/packages/rosenet-relay/lib/createRoseNetRelay.ts @@ -10,6 +10,7 @@ import { createLibp2p } from 'libp2p'; import { addEventListeners, + libp2pLoggerFactory, privateKeyToPeerId, } from '@rosen-bridge/rosenet-utils'; @@ -83,6 +84,7 @@ const createRoseNetRelay = async ({ name: 'rosenet-relay', version: packageJson.version, }, + logger: libp2pLoggerFactory(logger, config.debug?.libp2pComponents ?? []), }); logger.debug('RoseNet relay created'); diff --git a/packages/rosenet-relay/lib/types.ts b/packages/rosenet-relay/lib/types.ts index 7d9b310..02d06c1 100644 --- a/packages/rosenet-relay/lib/types.ts +++ b/packages/rosenet-relay/lib/types.ts @@ -9,4 +9,7 @@ export interface RoseNetRelayConfig { logger: AbstractLogger; whitelist: string[]; maxReservations?: number; + debug?: { + libp2pComponents?: string[]; + }; }