diff --git a/packages/logger/README.md b/packages/logger/README.md new file mode 100644 index 00000000..fe1439e4 --- /dev/null +++ b/packages/logger/README.md @@ -0,0 +1,31 @@ +# Topology Logger + +This package makes it easy to log messages in a structured way. + +## Usage + +This package is intended to be used as a dependency for the Topology Protocol. However, you can use it as a standalone package. For that, you can install it using: + +```bash +# yarn +yarn add @topology-foundation/logger + +# npm +npm install @topology-foundation/logger +``` + +### Build + +To build the package, you can run: + +```bash +yarn build +``` + +### Tests + +To run the tests, you can run: + +```bash +yarn test +``` diff --git a/packages/logger/package.json b/packages/logger/package.json new file mode 100644 index 00000000..f2f02f27 --- /dev/null +++ b/packages/logger/package.json @@ -0,0 +1,33 @@ +{ + "name": "@topology-foundation/logger", + "version": "0.2.1-0", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/topology-foundation/ts-topology.git" + }, + "type": "module", + "types": "./dist/src/index.d.ts", + "files": [ + "src", + "dist", + "!dist/test", + "!**/*.tsbuildinfo" + ], + "exports": { + ".": { + "types": "./dist/src/index.d.ts", + "import": "./dist/src/index.js" + } + }, + "scripts": { + "build": "tsc -b", + "clean": "rm -rf dist/ node_modules/", + "prepack": "tsc -b", + "test": "vitest" + }, + "dependencies": { + "loglevel": "^1.9.2", + "loglevel-plugin-prefix": "^0.8.4" + } +} diff --git a/packages/logger/src/index.ts b/packages/logger/src/index.ts new file mode 100644 index 00000000..4d93a4a5 --- /dev/null +++ b/packages/logger/src/index.ts @@ -0,0 +1,28 @@ +import loglevel from "loglevel"; +import prefix from "loglevel-plugin-prefix"; + +export interface LoggerOptions { + level?: loglevel.LogLevelDesc; +} + +export class Logger { + private log: loglevel.Logger; + // biome-ignore lint/suspicious/noExplicitAny: Do this to allow any method to be called on the logger + [key: string]: any; + + constructor(context: string, config?: LoggerOptions) { + this.log = loglevel.getLogger(context); + this.log.setLevel(config?.level || "info"); + prefix.reg(loglevel); + prefix.apply(this.log, { + template: "%n", + }); + + for (const method of Object.keys(this.log)) { + const logMethod = this.log[method as keyof loglevel.Logger]; + if (typeof logMethod === "function") { + this[method as string] = logMethod.bind(this.log); + } + } + } +} diff --git a/packages/logger/tsconfig.json b/packages/logger/tsconfig.json new file mode 100644 index 00000000..9cc8b37c --- /dev/null +++ b/packages/logger/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "dist" + }, + "include": ["src/**/*.ts"] +} diff --git a/packages/logger/typedoc.json b/packages/logger/typedoc.json new file mode 100644 index 00000000..c9c65c9c --- /dev/null +++ b/packages/logger/typedoc.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://typedoc.org/schema.json", + "includeVersion": true, + "entryPoints": ["src/index.ts"], + "readme": "README.md" +} diff --git a/packages/network/package.json b/packages/network/package.json index 785ce6ba..d9bea10d 100644 --- a/packages/network/package.json +++ b/packages/network/package.json @@ -49,6 +49,7 @@ "@libp2p/websockets": "^9.0.7", "@libp2p/webtransport": "^5.0.9", "@multiformats/multiaddr": "^12.3.1", + "@topology-foundation/logger": "^0.2.1-0", "it-length-prefixed": "^9.1.0", "it-map": "^3.1.1", "it-pipe": "^3.0.1", diff --git a/packages/network/src/node.ts b/packages/network/src/node.ts index 998d9345..b2464438 100644 --- a/packages/network/src/node.ts +++ b/packages/network/src/node.ts @@ -27,6 +27,7 @@ import { webSockets } from "@libp2p/websockets"; import * as filters from "@libp2p/websockets/filters"; import { webTransport } from "@libp2p/webtransport"; import { multiaddr } from "@multiformats/multiaddr"; +import { Logger, type LoggerOptions } from "@topology-foundation/logger"; import { type Libp2p, createLibp2p } from "libp2p"; import { fromString as uint8ArrayFromString } from "uint8arrays/from-string"; import { Message } from "./proto/topology/network/messages_pb.js"; @@ -34,6 +35,8 @@ import { uint8ArrayToStream } from "./stream.js"; export * from "./stream.js"; +let log: Logger; + // snake_casing to match the JSON config export interface TopologyNetworkNodeConfig { addresses?: string[]; @@ -41,6 +44,7 @@ export interface TopologyNetworkNodeConfig { bootstrap_peers?: string[]; browser_metrics?: boolean; private_key_seed?: string; + log_config?: LoggerOptions; } export class TopologyNetworkNode { @@ -52,6 +56,7 @@ export class TopologyNetworkNode { constructor(config?: TopologyNetworkNodeConfig) { this._config = config; + log = new Logger("topology::network", config?.log_config); } async start() { @@ -134,62 +139,52 @@ export class TopologyNetworkNode { this._pubsub = this._node.services.pubsub as PubSub; this.peerId = this._node.peerId.toString(); - console.log( - "topology::network::start: Successfuly started topology network w/ peer_id", + log.info( + "::start: Successfuly started topology network w/ peer_id", this.peerId, ); this._node.addEventListener("peer:connect", (e) => - console.log("::start::peer::connect", e.detail), + log.info("::start::peer::connect", e.detail), ); this._node.addEventListener("peer:discovery", (e) => { // current bug in v11.0.0 requires manual dial (https://github.com/libp2p/js-libp2p-pubsub-peer-discovery/issues/149) for (const ma of e.detail.multiaddrs) { this._node?.dial(ma); } - console.log("::start::peer::discovery", e.detail); + log.info("::start::peer::discovery", e.detail); }); this._node.addEventListener("peer:identify", (e) => - console.log("::start::peer::identify", e.detail), + log.info("::start::peer::identify", e.detail), ); } subscribe(topic: string) { if (!this._node) { - console.error( - "topology::network::subscribe: Node not initialized, please run .start()", - ); + log.error("::subscribe: Node not initialized, please run .start()"); return; } try { this._pubsub?.subscribe(topic); this._pubsub?.getPeers(); - console.log( - "topology::network::subscribe: Successfuly subscribed the topic", - topic, - ); + log.info("::subscribe: Successfuly subscribed the topic", topic); } catch (e) { - console.error("topology::network::subscribe:", e); + log.error("::subscribe:", e); } } unsubscribe(topic: string) { if (!this._node) { - console.error( - "topology::network::unsubscribe: Node not initialized, please run .start()", - ); + log.error("::unsubscribe: Node not initialized, please run .start()"); return; } try { this._pubsub?.unsubscribe(topic); - console.log( - "topology::network::unsubscribe: Successfuly unsubscribed the topic", - topic, - ); + log.info("::unsubscribe: Successfuly unsubscribed the topic", topic); } catch (e) { - console.error("topology::network::unsubscribe:", e); + log.error("::unsubscribe:", e); } } @@ -210,12 +205,12 @@ export class TopologyNetworkNode { const messageBuffer = Message.encode(message).finish(); await this._pubsub?.publish(topic, messageBuffer); - console.log( - "topology::network::broadcastMessage: Successfuly broadcasted message to topic", + log.info( + "::broadcastMessage: Successfuly broadcasted message to topic", topic, ); } catch (e) { - console.error("topology::network::broadcastMessage:", e); + log.error("::broadcastMessage:", e); } } @@ -226,7 +221,7 @@ export class TopologyNetworkNode { const messageBuffer = Message.encode(message).finish(); uint8ArrayToStream(stream, messageBuffer); } catch (e) { - console.error("topology::network::sendMessage:", e); + log.error("::sendMessage:", e); } } @@ -245,7 +240,7 @@ export class TopologyNetworkNode { const messageBuffer = Message.encode(message).finish(); uint8ArrayToStream(stream, messageBuffer); } catch (e) { - console.error("topology::network::sendMessageRandomTopicPeer:", e); + log.error("::sendMessageRandomTopicPeer:", e); } } diff --git a/packages/network/tsconfig.json b/packages/network/tsconfig.json index 9cc8b37c..48e3023f 100644 --- a/packages/network/tsconfig.json +++ b/packages/network/tsconfig.json @@ -3,5 +3,10 @@ "compilerOptions": { "outDir": "dist" }, + "references": [ + { + "path": "../logger" + } + ], "include": ["src/**/*.ts"] } diff --git a/packages/node/package.json b/packages/node/package.json index 00da6915..72d32d89 100644 --- a/packages/node/package.json +++ b/packages/node/package.json @@ -42,6 +42,7 @@ "@topology-foundation/blueprints": "0.2.1-0", "@topology-foundation/network": "0.2.1-0", "@topology-foundation/object": "0.2.1-0", + "@topology-foundation/logger": "0.2.1-0", "commander": "^12.1.0", "google-protobuf": "^3.21.2" } diff --git a/packages/node/src/rpc/index.ts b/packages/node/src/rpc/index.ts index 228d353a..30c58a19 100644 --- a/packages/node/src/rpc/index.ts +++ b/packages/node/src/rpc/index.ts @@ -1,6 +1,7 @@ import * as grpc from "@grpc/grpc-js"; import type { ServerUnaryCall, sendUnaryData } from "@grpc/grpc-js"; +import { Logger } from "@topology-foundation/logger"; import type { TopologyNode } from "../index.js"; import { TopologyRpcService } from "../proto/rpc_grpc_pb.js"; import type { @@ -13,6 +14,11 @@ import type { } from "../proto/rpc_pb.js"; export function init(node: TopologyNode) { + const log = new Logger( + "topology::rpc", + node.config?.network_config?.log_config, + ); + function subscribeCro( call: ServerUnaryCall, callback: sendUnaryData, @@ -80,7 +86,7 @@ export function init(node: TopologyNode) { "0.0.0.0:6969", grpc.ServerCredentials.createInsecure(), (_error, _port) => { - console.log("running grpc in port:", _port); + log.info("running grpc in port:", _port); }, ); } diff --git a/packages/node/src/version.ts b/packages/node/src/version.ts index edbab618..47452519 100644 --- a/packages/node/src/version.ts +++ b/packages/node/src/version.ts @@ -1 +1 @@ -export const VERSION = "0.2.0"; +export const VERSION = "0.2.1-0"; diff --git a/packages/node/tsconfig.json b/packages/node/tsconfig.json index 44104cf7..5d24764d 100644 --- a/packages/node/tsconfig.json +++ b/packages/node/tsconfig.json @@ -13,6 +13,9 @@ }, { "path": "../object" + }, + { + "path": "../logger" } ], "include": ["src/**/*.ts", "src/**/*.js"] diff --git a/packages/object/package.json b/packages/object/package.json index 91b25b78..b445967d 100644 --- a/packages/object/package.json +++ b/packages/object/package.json @@ -33,6 +33,7 @@ }, "dependencies": { "@bufbuild/protobuf": "^2.0.0", + "@topology-foundation/logger": "^0.2.1-0", "ts-proto": "^2.2.4" } } diff --git a/packages/object/src/wasm/compiler.ts b/packages/object/src/wasm/compiler.ts index d8482a2b..343fd4a2 100644 --- a/packages/object/src/wasm/compiler.ts +++ b/packages/object/src/wasm/compiler.ts @@ -3,10 +3,13 @@ - ABI */ import * as fs from "node:fs"; +import { Logger } from "@topology-foundation/logger"; import asc from "assemblyscript/asc"; export async function compileWasm(path: string) { - console.log("Compiling", path); + const log = new Logger("topology::wasm", { level: "info" }); + + log.info("Compiling", path); const { error, stderr } = await asc.main( [path, "--bindings=esm", "--outFile=/tmp/dist.wasm"], { @@ -29,8 +32,8 @@ export async function compileWasm(path: string) { ); if (error) { - console.log(`Compilation failed: ${error}`); - console.log(stderr.toString()); + log.info(`Compilation failed: ${error}`); + log.info(stderr.toString()); return new Uint8Array(); } @@ -39,6 +42,6 @@ export async function compileWasm(path: string) { fs.readFileSync("/tmp/dist.wasm"), ); // fs.unlinkSync('dist/tmp.wasm'); - console.log("Compilation successful", bytecode); + log.info("Compilation successful", bytecode); return bytecode; } diff --git a/packages/object/tsconfig.json b/packages/object/tsconfig.json index 9cc8b37c..48e3023f 100644 --- a/packages/object/tsconfig.json +++ b/packages/object/tsconfig.json @@ -3,5 +3,10 @@ "compilerOptions": { "outDir": "dist" }, + "references": [ + { + "path": "../logger" + } + ], "include": ["src/**/*.ts"] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a0daff27..b7fc9d38 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -45,16 +45,16 @@ importers: examples/canvas: dependencies: '@topology-foundation/blueprints': - specifier: 0.2.0 + specifier: 0.2.1-0 version: link:../../packages/blueprints '@topology-foundation/network': - specifier: 0.2.0 + specifier: 0.2.1-0 version: link:../../packages/network '@topology-foundation/node': - specifier: 0.2.0 + specifier: 0.2.1-0 version: link:../../packages/node '@topology-foundation/object': - specifier: 0.2.0 + specifier: 0.2.1-0 version: link:../../packages/object crypto-browserify: specifier: ^3.12.0 @@ -91,16 +91,16 @@ importers: examples/chat: dependencies: '@topology-foundation/blueprints': - specifier: 0.2.0 + specifier: 0.2.1-0 version: link:../../packages/blueprints '@topology-foundation/network': - specifier: 0.2.0 + specifier: 0.2.1-0 version: link:../../packages/network '@topology-foundation/node': - specifier: 0.2.0 + specifier: 0.2.1-0 version: link:../../packages/node '@topology-foundation/object': - specifier: 0.2.0 + specifier: 0.2.1-0 version: link:../../packages/object assemblyscript: specifier: ^0.27.29 @@ -143,13 +143,13 @@ importers: examples/grid: dependencies: '@topology-foundation/network': - specifier: 0.2.0 + specifier: 0.2.1-0 version: link:../../packages/network '@topology-foundation/node': - specifier: 0.2.0 + specifier: 0.2.1-0 version: link:../../packages/node '@topology-foundation/object': - specifier: 0.2.0 + specifier: 0.2.1-0 version: link:../../packages/object assemblyscript: specifier: ^0.27.29 @@ -198,16 +198,16 @@ importers: examples/local-bootstrap: dependencies: '@topology-foundation/blueprints': - specifier: 0.2.0 + specifier: 0.2.1-0 version: link:../../packages/blueprints '@topology-foundation/network': - specifier: 0.2.0 + specifier: 0.2.1-0 version: link:../../packages/network '@topology-foundation/node': - specifier: 0.2.0 + specifier: 0.2.1-0 version: link:../../packages/node '@topology-foundation/object': - specifier: 0.2.0 + specifier: 0.2.1-0 version: link:../../packages/object assemblyscript: specifier: ^0.27.29 @@ -254,12 +254,21 @@ importers: version: 4.1.2 devDependencies: '@topology-foundation/object': - specifier: 0.2.0 + specifier: 0.2.1-0 version: link:../object assemblyscript: specifier: ^0.27.29 version: 0.27.30 + packages/logger: + dependencies: + loglevel: + specifier: ^1.9.2 + version: 1.9.2 + loglevel-plugin-prefix: + specifier: ^0.8.4 + version: 0.8.4 + packages/network: dependencies: '@bufbuild/protobuf': @@ -316,6 +325,9 @@ importers: '@multiformats/multiaddr': specifier: ^12.3.1 version: 12.3.1 + '@topology-foundation/logger': + specifier: ^0.2.1-0 + version: link:../logger it-length-prefixed: specifier: ^9.1.0 version: 9.1.0 @@ -354,13 +366,16 @@ importers: specifier: ^2.1.3 version: 2.1.3 '@topology-foundation/blueprints': - specifier: 0.2.0 + specifier: 0.2.1-0 version: link:../blueprints + '@topology-foundation/logger': + specifier: 0.2.1-0 + version: link:../logger '@topology-foundation/network': - specifier: 0.2.0 + specifier: 0.2.1-0 version: link:../network '@topology-foundation/object': - specifier: 0.2.0 + specifier: 0.2.1-0 version: link:../object commander: specifier: ^12.1.0 @@ -390,6 +405,9 @@ importers: '@bufbuild/protobuf': specifier: ^2.0.0 version: 2.2.0 + '@topology-foundation/logger': + specifier: ^0.2.1-0 + version: link:../logger ts-proto: specifier: ^2.2.4 version: 2.2.5 @@ -3766,6 +3784,13 @@ packages: resolution: {integrity: sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==} engines: {node: '>=18'} + loglevel-plugin-prefix@0.8.4: + resolution: {integrity: sha512-WpG9CcFAOjz/FtNht+QJeGpvVl/cdR6P0z6OcXSkr8wFJOsV2GRj2j10JLfjuA4aYkcKCNIEqRGCyTife9R8/g==} + + loglevel@1.9.2: + resolution: {integrity: sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==} + engines: {node: '>= 0.6.0'} + long@5.2.3: resolution: {integrity: sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==} @@ -9487,6 +9512,10 @@ snapshots: chalk: 5.3.0 is-unicode-supported: 1.3.0 + loglevel-plugin-prefix@0.8.4: {} + + loglevel@1.9.2: {} + long@5.2.3: {} loose-envify@1.4.0: