From 2f325fd8d52543287d923d42741f0d87da01b041 Mon Sep 17 00:00:00 2001 From: Ben Houston Date: Sat, 22 Jul 2023 11:16:22 -0400 Subject: [PATCH] cleanup readme, simplify log output in exec-graph (add colors), and ensure source maps work on cli apps. --- README.md | 108 +++++++++++++++--------- apps/exec-graph/bin/cli.js | 2 +- apps/exec-graph/src/index.ts | 15 +++- apps/export-node-spec/bin/cli.js | 2 +- packages/core/src/Diagnostics/Logger.ts | 39 +++++++-- tsconfig.json | 3 +- 6 files changed, 120 insertions(+), 49 deletions(-) diff --git a/README.md b/README.md index fcfd9672..7c441362 100644 --- a/README.md +++ b/README.md @@ -12,9 +12,9 @@ Another neat fact about behavior graphs is that they offer a sand boxed executio ## Documentation -* [Extending the Value System](/docs/Values.md) -* [Types Of Nodes](/docs/TypesOfNodes.md) -* [Abstractions and Drivers](/docs/Abstractions.md) +- [Extending the Value System](/docs/Values.md) +- [Types Of Nodes](/docs/TypesOfNodes.md) +- [Abstractions and Drivers](/docs/Abstractions.md) ## Community Resources @@ -34,21 +34,21 @@ This library, while small, contains a nearly complete implementation of behavior ### Features -* **Customizable** While this library contains a lot of nodes, you do not have to expose all of them. For example, just because this supports for-loops and state, does not mean you have to register that node type as being available. -* **Type Safe** This library is implemented in TypeScript and fully makes use of its type safety features. -* **Small** This is a very small library with no external dependencies. -* **Simple** This library is implemented in a forward fashion without unnecessary complexity. -* **High Performance** Currently in performance testing, the library achieves over 2M node executions per second. +- **Customizable** While this library contains a lot of nodes, you do not have to expose all of them. For example, just because this supports for-loops and state, does not mean you have to register that node type as being available. +- **Type Safe** This library is implemented in TypeScript and fully makes use of its type safety features. +- **Small** This is a very small library with no external dependencies. +- **Simple** This library is implemented in a forward fashion without unnecessary complexity. +- **High Performance** Currently in performance testing, the library achieves over 2M node executions per second. ### Node Types -* **Events** You can implement arbitrary events that start execution: Start, Tick -* **Actions** You can implement actions that trigger animations, scene scene variations, or update internal state: Log -* **Logic** You can do arithmetic, trigonometry as well as vector operations and string manipulation: Add, Subtract, Multiply, Divide, Pow, Exp, Log, Log2, Log10, Min, Max, Round, Ceil, Floor, Sign, Abs, Trunc, Sqrt, Negate, And, Or, Not, ==, >, >=, <, <=, isNan, isInfinity, concat, includes. -* **Queries** You can query the state from the system. -* **Flow Control** Control execution flow using familiar structures: Branch, Delay, Debounce, Throttle, FlipFlop, Sequence, Gate, MultiGate, DoOnce, DoN, ForLoop -* **Variables** You can create, set and get variable values. -* **Custom Events** You can create, listen to and trigger custom events. +- **Events** You can implement arbitrary events that start execution: Start, Tick +- **Actions** You can implement actions that trigger animations, scene scene variations, or update internal state: Log +- **Logic** You can do arithmetic, trigonometry as well as vector operations and string manipulation: Add, Subtract, Multiply, Divide, Pow, Exp, Log, Log2, Log10, Min, Max, Round, Ceil, Floor, Sign, Abs, Trunc, Sqrt, Negate, And, Or, Not, ==, >, >=, <, <=, isNan, isInfinity, concat, includes. +- **Queries** You can query the state from the system. +- **Flow Control** Control execution flow using familiar structures: Branch, Delay, Debounce, Throttle, FlipFlop, Sequence, Gate, MultiGate, DoOnce, DoN, ForLoop +- **Variables** You can create, set and get variable values. +- **Custom Events** You can create, listen to and trigger custom events. ### Designed for Integration into Other Systems @@ -75,7 +75,7 @@ The example behavior graphs are in the `/examples` folder. You can execute these The main syntax is this one: ```zsh -npm run exec-graph ../../graphs/[examplename].json +npx exec-graph ./graphs/[examplename].json ``` Here are some example graphs in their native JSON form: @@ -88,9 +88,13 @@ Print out the text "Hello World!" as soon as the graph starts up! Console output: -```zsh -npm run exec-graph ../../graphs/core/HelloWorld.json +```sh +npx exec-graph ./graphs/core/HelloWorld.json +``` +Console output: + +```sh Hello World! ``` @@ -102,9 +106,13 @@ In this example, we use set a variable and also listen to when it changes. Console output: -```zsh -> npm run exec-graph ../../graphs/core/variables/Changed.json +```sh +npx exec-graph ./graphs/core/variables/Changed.json +``` + +Console output: +```sh 391 ``` @@ -114,11 +122,15 @@ This example shows how to branching execution works. The "flow/branch" node has [/graphs/core/flow/Branch.json](/graphs/core/flow/Branch.json) -Console output: +Command: -```zsh -> npm run exec-graph ../../graphs/core/flow/Branch.json +```sh +npx exec-graph ./graphs/core/flow/Branch.json +``` +Console output: + +```sh Condition is false! ``` @@ -128,11 +140,15 @@ This shows how to create math formulas in logic nodes. In this case the equation [/graphs/core/logic/Polynomial.json](/graphs/core/logic/Polynomial.json) -Console output: +Command: -```zsh -> npm run exec-graph ../../graphs/core/logic/Polynomial.json +```sh +npx exec-graph ./graphs/core/logic/Polynomial.json +``` + +Console output: +```sh -9 ``` @@ -142,11 +158,15 @@ Behave-Graph support asynchronous nodes. These are nodes which will continue exe [/graphs/core/async/Delay.json](/graphs/core/async/Delay.json) -Console output: +Command: -```zsh -> npm run exec-graph ../../graphs/core/async/Delay.json +```sh +npx exec-graph ./graphs/core/async/Delay.json +``` + +Console output: +```sh Waiting... One Second Later! ``` @@ -157,11 +177,15 @@ Building upon waiting for downstream nodes to execute, you can also execute For [/graphs/core/flow/ForLoop.json](/graphs/core/flow/ForLoop.json) -Console output: +Command: -```zsh -> npm run exec-graph ../../graphs/core/flow/ForLoop.json +```sh +npx exec-graph ./graphs/core/flow/ForLoop.json +``` + +Console output: +```sh Starting For Loop... Loop Body! Loop Body! @@ -184,9 +208,13 @@ You can register custom events, trigger then and listen on them. Console output: -```zsh -> npm run exec-graph ../../graphs/core/events/CustomEvents.json +```sh +npx exec-graph ./graphs/core/events/CustomEvents.json +``` + +Console output: +```sh myCustomEvent Fired! myCustomEvent Fired! myCustomEvent Fired! @@ -200,11 +228,15 @@ Here is a test of 10,000,000 iteration for loop: [/graphs/core/flow/PerformanceTest.json](/graphs/core/flow/PerformanceTest.json) -Here is the console output, when running with profiling (-p): +Here is the command running with profiling (-p): -```zsh -> npm run exec-graph ../../graphs/core/flow/PerformanceTest.json -- -- -p +```sh +npx exec-graph ./graphs/core/flow/PerformanceTest.json -p +``` + +Console output: +```sh Starting 10,000,000 iteration for-loop... 1,000,000 more iterations... 1,000,000 more iterations... @@ -218,5 +250,5 @@ Starting 10,000,000 iteration for-loop... 1,000,000 more iterations... Completed all iterations! - 30000013 nodes executed in 2.98 seconds, at a rate of 10067118 steps/second + Profile Results: 30000014 nodes executed in 2.742 seconds, at a rate of 10940924 steps/second ``` diff --git a/apps/exec-graph/bin/cli.js b/apps/exec-graph/bin/cli.js index 70274bbb..8c6aa33c 100755 --- a/apps/exec-graph/bin/cli.js +++ b/apps/exec-graph/bin/cli.js @@ -1,4 +1,4 @@ -#!/usr/bin/env node +#!/usr/bin/env node --enable-source-maps import { main } from '../dist/index.js'; diff --git a/apps/exec-graph/src/index.ts b/apps/exec-graph/src/index.ts index 3a87c1c1..8763d6cb 100644 --- a/apps/exec-graph/src/index.ts +++ b/apps/exec-graph/src/index.ts @@ -6,6 +6,7 @@ import { Engine, ILifecycleEventEmitter, Logger, + LogLevel, ManualLifecycleEventEmitter, parseSafeFloat, readGraphFromJSON, @@ -24,7 +25,7 @@ const { name, version } = packageInfo as { name: string; version: string }; type ProgramOptions = { upgrade?: boolean; - trace?: boolean; + logLevel?: number; dryRun?: boolean; profile?: boolean; iterations: string; @@ -49,6 +50,10 @@ async function execGraph({ }) ); + if (programOptions.logLevel) { + Logger.logLevel = programOptions.logLevel as LogLevel; + } + const graphJsonPath = jsonPattern; Logger.verbose(`reading behavior graph: ${graphJsonPath}`); const textFile = await fs.readFile(graphJsonPath); @@ -77,7 +82,8 @@ async function execGraph({ Logger.verbose('creating behavior graph'); const engine = new Engine(graph.nodes); - if (programOptions.trace) { + // do not log at all to the verbose if not verbose is not enabled, makes a big performance difference. + if (programOptions.logLevel === LogLevel.Verbose) { engine.onNodeExecutionStart.addListener((node) => Logger.verbose(`<< ${node.description.typeName} >> START`) ); @@ -99,6 +105,7 @@ async function execGraph({ Logger.verbose('executing all (async)'); await engine.executeAllAsync(5); + Logger.verbose(' completed'); } if (lifecycleEventEmitter.tickEvent.listenerCount > 0) { @@ -110,6 +117,7 @@ async function execGraph({ Logger.verbose('executing all (async)'); // eslint-disable-next-line no-await-in-loop await engine.executeAllAsync(5); + Logger.verbose(' completed'); } } @@ -119,6 +127,7 @@ async function execGraph({ Logger.verbose('executing all (async)'); await engine.executeAllAsync(5); + Logger.verbose(' completed'); } if (programOptions.profile) { @@ -140,7 +149,7 @@ export const main = async () => { .name(name) .version(version) .argument('', 'path to the behavior-graph json to execute') - .option('-t, --trace', `trace node execution`) + .option('-l, --logLevel ', `trace node execution`, '1') .option('-p, --profile', `profile execution time`) .option('-d, --dryRun', `do not run graph`) .option( diff --git a/apps/export-node-spec/bin/cli.js b/apps/export-node-spec/bin/cli.js index 70274bbb..8c6aa33c 100755 --- a/apps/export-node-spec/bin/cli.js +++ b/apps/export-node-spec/bin/cli.js @@ -1,4 +1,4 @@ -#!/usr/bin/env node +#!/usr/bin/env node --enable-source-maps import { main } from '../dist/index.js'; diff --git a/packages/core/src/Diagnostics/Logger.ts b/packages/core/src/Diagnostics/Logger.ts index 4f90524b..c4fde396 100644 --- a/packages/core/src/Diagnostics/Logger.ts +++ b/packages/core/src/Diagnostics/Logger.ts @@ -2,7 +2,27 @@ import { EventEmitter } from '../Events/EventEmitter.js'; +export enum LogLevel { + Verbose = 0, + Info = 1, + Warn = 2, + Error = 3 +} + +export enum PrefixStyle { + None = 0, + Time = 1 +} + +const Reset = '\x1b[0m'; +const FgRed = '\x1b[31m'; +const BgYellow = '\x1b[43m'; +const Dim = '\x1b[2m'; + export class Logger { + static logLevel = LogLevel.Info; + static prefixStyle = PrefixStyle.None; + public static readonly onVerbose = new EventEmitter(); public static readonly onInfo = new EventEmitter(); public static readonly onWarn = new EventEmitter(); @@ -10,19 +30,28 @@ export class Logger { static { const prefix = () => { - return new Date().toLocaleTimeString().padStart(11, '0'); + switch (Logger.prefixStyle) { + case PrefixStyle.None: + return ''; + case PrefixStyle.Time: + return new Date().toLocaleTimeString().padStart(11, '0') + ' '; + } }; + Logger.onVerbose.addListener((text: string) => { - console.log(prefix() + ` VERB: ${text}`); + if (Logger.logLevel > LogLevel.Verbose) return; + console.log(prefix() + `${Dim}${text}${Reset}`); }); Logger.onInfo.addListener((text: string) => { - console.log(prefix() + ` INFO: ${text}`); + if (Logger.logLevel > LogLevel.Info) return; + console.log(prefix() + `${text}`); }); Logger.onWarn.addListener((text: string) => { - console.warn(prefix() + ` WARN: ${text}`); + if (Logger.logLevel > LogLevel.Warn) return; + console.warn(prefix() + `${BgYellow}${text}${Reset}`); }); Logger.onError.addListener((text: string) => { - console.error(prefix() + ` ERR: ${text}`); + console.error(prefix() + `${FgRed}${text}}${Reset}`); }); } diff --git a/tsconfig.json b/tsconfig.json index c7b41eac..421135d7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,7 +2,8 @@ "compilerOptions": { "paths": { "@behave-graph/core": ["./packages/core/"], - "@behave-graph/flow": ["./packages/flow/"] + "@behave-graph/flow": ["./packages/flow/"], + "@behave-graph/scene": ["./packages/scene/"] }, "outDir": "dist", "target": "ES2020",