{"id":26997674,"url":"https://github.com/risq/investigator","last_synced_at":"2025-09-04T00:42:41.545Z","repository":{"id":57275543,"uuid":"45067301","full_name":"risq/investigator","owner":"risq","description":"Interactive and asynchronous logging tool for Node.js. An easier way to log \u0026 debug complex requests directly from the command line (experimental).","archived":false,"fork":false,"pushed_at":"2015-11-04T21:23:09.000Z","size":250,"stargazers_count":158,"open_issues_count":0,"forks_count":2,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-07-07T00:42:09.788Z","etag":null,"topics":["async","cli","command-line-tool","debug","logging","nodejs"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/risq.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-10-27T20:13:26.000Z","updated_at":"2025-05-23T02:14:20.000Z","dependencies_parsed_at":"2022-09-15T19:10:34.383Z","dependency_job_id":null,"html_url":"https://github.com/risq/investigator","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/risq/investigator","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/risq%2Finvestigator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/risq%2Finvestigator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/risq%2Finvestigator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/risq%2Finvestigator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/risq","download_url":"https://codeload.github.com/risq/investigator/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/risq%2Finvestigator/sbom","scorecard":{"id":777373,"data":{"date":"2025-08-11","repo":{"name":"github.com/risq/investigator","commit":"9372477a46cf13614b2324e417b953ed1b46f4ce"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Code-Review","score":0,"reason":"Found 0/20 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}}]},"last_synced_at":"2025-08-23T03:56:33.160Z","repository_id":57275543,"created_at":"2025-08-23T03:56:33.161Z","updated_at":"2025-08-23T03:56:33.161Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273534463,"owners_count":25122676,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-03T02:00:09.631Z","response_time":76,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["async","cli","command-line-tool","debug","logging","nodejs"],"created_at":"2025-04-04T02:18:59.407Z","updated_at":"2025-09-04T00:42:41.270Z","avatar_url":"https://github.com/risq.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# investigator\nInteractive and asynchronous logging tool for Node.js. An easier way to log \u0026 debug complex requests directly from the command line. Still experimental !\n\n![investigator](https://cloud.githubusercontent.com/assets/5665322/10861471/d38bedda-7f80-11e5-9bb7-19801c14c961.gif)\n\n## Usage\n#### Nodes\n`investigator` uses a node based logging system. Log nodes (*agents*) can be nested to help organizing the different steps, synchronous or not, of the process. An `agent` is defined by its name and can be retrieved at any time in the scope of its parent agent.\n\n![investigator-nodes](https://cloud.githubusercontent.com/assets/5665322/10861540/267ff6e6-7f84-11e5-847a-5b7d395dfb34.png)\n\n```js\nimport {agent} from 'investigator';\n\nconst requestAgent = agent('request');\nconst getUserAgent = requestAgent.child('getUser')\n  .log('Retrieving user from db...');\n\n// ...\n\ngetUserAgent.success('Done !');\n// Or: requestAgent.child('getUser').success('Done !');\n```\n\n#### Asynchronous logging\n`async` agents are particular nodes which may be resolved or rejected to provide a feedback of their fulfillment.\n\n![investigator-async](https://cloud.githubusercontent.com/assets/5665322/10861606/e00908b2-7f86-11e5-862a-ab56505d3ee3.png)\n\n```js\nimport {agent} from 'investigator';\n\nconst requestAgent = agent('request');\n\n// Creates an async child agent\nconst getUserAgent = requestAgent.async('getUser')\n  .log('Retrieving user from db...');\n\nmyAsynchronousFunction().then(() =\u003e {\n  getUserAgent.resolve('Done !');\n}).catch((err) =\u003e {\n  getUserAgent.reject(err);\n});\n```\n\n#### Inspector\n`investigator` provides an `inspector` module to allow deep object logging directly in the command line interface, like a browser devtools inspector. It also displays the current stack trace of each log.\n\n![investigator-inspector](https://cloud.githubusercontent.com/assets/5665322/10861607/e00c7506-7f86-11e5-8bd8-d3ae7a072c9d.png)\n\n## Installing\nUse `npm install investigator` to install locally. See [Usage](#usage) and [API Reference](#api-reference) for more information.\n\n## Shortcuts\nIn the command line interface, the following shortcuts are available:\n- Scroll up and down with `up arrow`, `down arrow`, or mouse wheel. You may also click on a row to select it.\n- Open **Inspector** with `i` (inspect the currently selected row).\n- Scroll to bottom with `b`\n- Enable auto-scroll with `s`. Disable by pressing an arrow key.\n\n## Testing \u0026 developing\nClone the project with `git clone git@github.com:risq/investigator.git`.\n\nInstall dependencies with `npm install`.\n\nLaunch the example with `node examples/index.js`.\n\nYou can build the project (transpiling to ES5) with `npm run build`.\n\n## TODO (non-exhaustive list)\n- [ ] Log as traditional `console.log` (or use a multi-transport logging lib like [winston](https://github.com/winstonjs/winston)), then parse output stream in real time (or from a log file) with `investigator`.\n- [ ] Improve UI, navigation \u0026 controls in the CLI.\n- [ ] Add some performance monitoring.\n- [ ] Improve CLI performance for long time logging (avoid memory leaks).\n- [ ] Allow client-side logging via WebSockets.\n\n## API Reference\n### Investigator\n##### `investigator.agent(String name [, data])` -\u003e `Agent`\nCreates a new *root* agent, with a given `name`. Data parameters of any type can also be passed to be logged into the command line interface.\n\n```js\nimport {agent} from 'investigator';\n\nonRequest(req, res) {\n  const requestAgent = agent('request', req.id, req.url);\n}\n```\n\n### Agent\n##### `agent.log(data [, data])` -\u003e `Agent`\nLog passed data parameters under the given agent node. Returns the same agent (so it can be chained).\n\n```js\nimport {agent} from 'investigator';\n\nonRequest(req, res) {\n  const requestAgent = agent('request', req.id, req.url);\n  requestAgent.log('Hello')\n    .log('World');\n}\n```\n\n##### `agent.success(data [, data])` -\u003e `Agent`\nLog passed data parameters under the given agent node, as a success (displayed in green). Returns the same agent (so it can be chained).\n\n##### `agent.warn(data [, data])` -\u003e `Agent`\nLog passed data parameters under the given agent node, as a warning (displayed in yellow). Returns the same agent (so it can be chained).\n\n##### `agent.error(data [, data])` -\u003e `Agent`\nLog passed data parameters under the given agent node, as an error (displayed in red). Returns the same agent (so it can be chained).\n\n##### `agent.child(name [, data])` -\u003e `Agent`\nReturns a child of the current agent, defined by its name. If a child with the given name already exists on the agent, it will be returned. If not, it will be created.\n\nData objects can be passed as parameters and will be logged on the child's context.\n\n```js\nimport {agent} from 'investigator';\n\nonRequest(req, res) {\n  const requestAgent = agent('request', req.id, req.url);\n\n  if (req.url === '/user/login') {\n    requestAgent.child('login', 'Logging in...');\n\n    if (validate(req.user, req.password)) {\n      requestAgent.child('login')\n        .success('Login data validated !');\n    } else {\n      requestAgent.child('login')\n        .error('Error validating user data.')\n    }\n  }\n}\n```\n\n##### `agent.async(name [, data])` -\u003e `Agent`\nReturns a **asynchronous** child of the current agent, defined by its name. If a child with the given name already exists on the agent, it will be returned. If not, it will be created.\n\nData objects can be passed as parameters and will be logged on the child's context.\n\nAn async agent has `.resolve()` and `.reject()` methods, to keep track of its fulfillment.\n\n```js\nimport {agent} from 'investigator';\n\nonRequest(req, res) {\n  const requestAgent = agent('request', req.id, req.url);\n\n  if (req.url === '/user/login') {\n    requestAgent.child('login', 'Logging in...');\n\n    authUser(req.user, req.password).then(() =\u003e {\n      requestAgent.child('login')\n        .success('Authentication succeeded !');\n    }).catch((err) =\u003e {\n      requestAgent.child('login')\n        .error('Error validating user data.')\n    });\n  }\n}\n```\n\n##### `agent.resolve(data [, data])` -\u003e `Agent`\nResolves an **async** agent. Log data parameters under the given agent node, as a success. Returns the same agent (so it can be chained).\n\nAn async agent can only be resolved or rejected once.\n\n##### `agent.reject(data [, data])` -\u003e `Agent`\nResolves an **async** agent. Log data parameters under the given agent node, as an error. Returns the same agent (so it can be chained).\n\nAn async agent can only be resolved or rejected once.\n\n## Contributing\nFeel free to contribute ! Issues and pull requests are highly welcomed and appreciated.\n\n## License\nThe MIT License (MIT)\n\nCopyright (c) 2015 Valentin Ledrapier\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frisq%2Finvestigator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frisq%2Finvestigator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frisq%2Finvestigator/lists"}