Code Monkey home page Code Monkey logo

report-toolkit's Introduction

report-toolkit

A toolkit for consumers of Node.js diagnostic Reports

Build Status Latest Version Licensed Apache-2.0

Features

  • Run heuristics ("Rules") against diagnostic reports to uncover issues needing attention
    • Comes with a set of built-in Rules and a "recommended" configuration
    • Custom, extendable, and shareable Rules
  • Purpose-built, "smart" diagnostic report diffing
    • "What has changed from last report?"
    • Ignores fields that don't matter
  • Automatically redacts sensitive information from report output
    • Redacts cloud provider tokens, session IDs, etc., from environment variables
    • Redaction available as a single operation--use this before sending the report somewhere else!
  • A friendly, colorful command-line interface
  • Two public APIs: Promise-based and Observable-based

Other Stuff Worth Mentioning

  • A choice of output formats:
    • Tabular, human-readable output
    • JSON
    • CSV
  • Handles one or more report files
  • Written using ES modules to facilitate bundling as library for the web

Installation & Usage

๐Ÿšจ WARNING! ๐Ÿšจ

As per semantic versioning, report-toolkit should be considered experimental until it reaches v1.0.0. Until then, the command-line options, programmatic API or output could change at any time.

report-toolkit is unlikely to reach v1.0.0 until Diagnostic Reports become a stable Node.js API.

For CLI Usage

npx report-toolkit --help

or install globally:

npm install -g report-toolkit && \
report-toolkit --help

For Usage as a Library

npm install report-toolkit

and:

// my-app.js
const {inspect} = require('report-toolkit');

async function main() {
  const report = JSON.parse(process.report.getReport());
  // configuration automatically loaded from `.rtkrc.js` in CWD
  const results = await inspect(report);
  if (results.length) {
    results.forEach(result => {
      // log problem and associated rule ID
      console.log(`${result.message} (${result.id})`);
    });
  } else {
    console.log('no problems!');
  }
}

main();

About Diagnostic Reports

Diagnostic Reports landed as an experimental feature in Node.js v11.8.0.

The Node.js documentation describes reports:

"The report is intended for development, test and production use, to capture and preserve information for problem determination. It includes JavaScript and native stack traces, heap statistics, platform information, resource usage etc. With the report option enabled, diagnostic reports can be triggered on unhandled exceptions, fatal errors and user signals, in addition to triggering programmatically through API calls."

Contributing

Roadmap

Future Ideas, Extensions & Use Cases

  • report-toolkit-as-a-service: send reports to a service which returns inspection or diff results
  • Client-side ("in your app") wrapper for report transmission or direct invocation of report-toolkit
  • Use CLI or API to trigger report generation from a running node process & interpret results; could be real-time
  • Easy cloud deployment & integration
  • "Connectors" for logging, tracing & observability tools
  • Web or Electron-based GUI
  • Adapters for frameworks
  • IDE/editor integration: generate a report from running process, view results

See Also

Maintainer(s)

License

Copyright ยฉ 2019-2020, IBM. Licensed Apache-2.0

report-toolkit's People

Contributors

boneskull avatar danielrosenwasser avatar dependabot[bot] avatar gdorsi avatar imgbot[bot] avatar qualitymanifest avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

report-toolkit's Issues

CLI should not pull in rules pkg

The rules pkg should ideally be completely transparent to the CLI. core should handle whatever the CLI is doing directly with the rules.

determine what to do with duplicate messages

This is an edge case, but what should we do if a Rule returns more than one equivalent message? This is ostensibly going to be a bug in the Rule implementation, but is there a use-case for this? Should we just silently dedupe, or throw an exception, something else?

consistent public API

The public APIs should be consistent and minimal, and there should be feature-parity between the Observable-based API and Promise-based API.

Polish this up before initial release

plugins should have transformers

this means that @report-toolkit/transformers should be a plugin.

plugins should not only allow for rule defs, but transformer defs as well.

update #51 to reflect this change

transformer chain tests

We need a matrix of tests for potential transformer chains to ensure they work as expected

switch from esm to rollup for most packages

We want browser support in every package which does not do Node.js-specific stuff (essentially, everything except @gnostic/cli and @gnostic/fs).

Rollup seems like an obvious choice, since most packages are intended to be used as libraries.

It may make sense to use Rollup in the above two modules for consistency, but it's of less importance.

documentation example: async rule

Since Rule inspection functions can return a Promise, we ought to provide an example of this. currently the builtins are all synchronous.

json transformer should use field labels

wherever possible, use the field labels instead of properties in the json transformer

list-rules command should have keys rule and description, not id and description.

(note that the keys should be normalized to lower case)

formatter / transformer design

I was operating under the definition that a formatter took a raw report and returned it in some specific output format, and a transformer took a raw report and output some other shape of data, and was intended to be piped through to a formatter.

But, the original transformer (numeric) was intended to essentially filter (and restructure) a report--and it can only really be used with the pipe formatter. It doesn't really make sense to use the pipe formatter outside of the numeric context unless you wanted to consume it via something like a newline-delimited readable stream.

anyhow... I'm thinking perhaps we don't need to differentiate between formatters and transformers. indeed it makes things more complex for the user. not sure.

perhaps some of these combinations could be shortcuts or prerolled configurations.

UPDATE: I've done some work here on the transformers, but there's work to re-integrate them into some of the commands:

  • list-rules
  • inspect
  • diff

make transformer initialization less horrid

"The configuration stuff could be some of the worst code I've ever
written. There's more refactoring to be done here; we should load the
transformers first using defaults & user-supplied configuration, THEN
we should validate the chain. Right now we're trying to do both at once
which is just vile"

fix default widths

Looks like the terminal widths aren't stretching how they should across various commands

Might also want to refactor this, because it should work w/o having to manually pass maxWidth, etc.

explicitly support third-party Rules

We have some functions in @report-toolkit/fs that are presently not used. This is due, in part, to bundling a CJS module.

At present, only built-in Rules are accessible via the inspect CLI command. This is a bug. We need to be able to load third-party rules via require(), at minimum.

Ensure the present functionality supports this (see fs-rule-loader.js), and write tests.

new transformer: filter

This is a general-purpose transformer which will "pick" fields from the report.

Allow use of keypaths (foo.bar.baz).

This is likely most useful when combined with another transformer, but it doesn't need to be used this way

allow multiple transformers

the user should be able to use multiple transformers (in order).

this might get a little complex, because transformers expect a Report as input. this is starting to look like readable/writable streams a bit, where you can't read the output of a writable stream, unless it's a transform stream.

not that I'm not advocating for use of Node.js streams, as the horror of working with them is the reason I'm using observables

split UMD bundles?

I'm not sure of the best way to distribute these. Right now, it just stuffs all dependencies into the resulting bundle, which is not optimal.

Maybe we shouldn't worry about it, because any consuming app will use ES modules and do its own tree-shaking & bundling?

guided usage ("wizard")

Maybe this is something like a "wizard".

Developers may need to analyze reports but don't know exactly what they need; rather they know something bad is happening. At minimum they might know that e.g., "the process is running out of memory." we want to create optimized solutions to specific problems.

Provide some way for a user to describe a problem (perhaps from a list of options), then rtk will use its facilities to help solve the issue. this might involve generating a reusable configuration which can then be subsequently applied to more reports, or maybe it's configs alongside the rtk:recommended config. (note: rtk:recommended might not be useful)

docs: tutorials

HOWTOs on each of the command-line options:

  1. inspect
    1. each built-in-rule
    2. single file
    3. multiple files
  2. redact
    1. single file
    2. multiple files
  3. transform
    1. each built-in transform on a single file
    2. example of combining inspect with transformers
    3. example of combining diff with transformers
  4. diff

core API must provide access to transformations

Currently, the CLI imports @report-toolkit/transformers directly, and it should not--it should only interact with @report-toolkit/core. Abstract the current functionality it's using in core.

provide individual executables for each command (maybe)

a la gnostic-rebase, gnostic-inspect, etc., in addition to the complete gnostic CLI.

This is best accomplished by:

  1. breaking up the CLI into multiple "command packages"
  2. stuffing common config into its own package
  3. using gnostic package as the main CLI, which would depend upon all of the other command packages

This would allow a user to install just gnostic-rebase, for example.

custom redaction

redact needs ability to read a config file and redact against user-supplied regexes.

hash stacktraces

one use case for gnostic is post-mortem debugging. when analyzing stacktraces from a crashed process, it's useful to know if a particular exception thrown is unique. we can determine the uniqueness of any given traceback by removing variable information and distilling to the list of lines in the stack itself, then taking a hash of the result.

provide a command which accepts a report and outputs a hash of the stack trace.

Ref: https://github.com/hekike/node-report-analytics

transformer tests could use a helper

These are unit tests, but the transform function that each exports is only ever called by the Transformer class, which applies any default options defined within a transformer. Calling these functions directly does not apply those defaults.

The reasoning behind defining defaults in the meta object is threefold:

  1. We can merge any custom options deeply within them, which would otherwise be boilerplate in each transform function
  2. Defaults can (in the future) and should be applied via schema validation (ajv). If the merging of options happened within the transform function itself, this would not be possible.
  3. When two transformers are chained together, the next transformer pulls in defaults from the previous one. This allows a chain of something like diff -> table to have its output defined by the diff transformer--the table transformer does not and cannot know how to display this data.

establish convention for use of constants

Various packages have constants in them, and they should all export these in a similar shape.

It's absolutely useful to be able to iterate over a set of constants exported from a package. For example, names of formatters or transformers. If a package has a single entry point, then constants-as-named-exports won't get us there, because those exports may not all be constants!

I'm thinking this should be sufficient:

/**
 * @enum {string}
 */
export const constants = {
  FOO: 'foo',
  BAR: 'bar',
  BAZ: 'baz'
};

A consumer can:

import {constants as fooConstants} from '@report-toolkit/foo';

disable ESLint rule monorepo/no-internal-imports

I had enabled this because it:

  1. restricts imports to a set of whitelisted imports via module-level exports
  2. discourages consumers from reaching into the guts of any given package and doing weird stuff

But it's plainly inconvenient:

import {observable} from '@report-toolkit/common';
const {all, the, stuff, I, need, to, use} = observable;

where it'd be nicer to just:

import {all, the, stuff, I, need, to, use} from '@report-toolkit/common/observable';

Now, each package puts everything in 'src/', so we'd want to actually move the files out of there and into the package root.

This same thing should be possible when using the CJS bundle. I'm not sure the best way to accomplish that, but I think we can look at RxJS as an example, because I believe it allows this. It doesn't bundle itself for CJS, however (it just compiles via TypeScript), which means our Rollup configuration may be limited to generating UMD bundles for browser use. We could then just use @babel/cli to transpile for CJS.

sorting output should be done in the CLI

Currently, sorting is done in the core API (toReportFromObject), which doesn't make a lot of sense:

  1. sorting must concatenate the stream to an array, which means there's a bottleneck
  2. internally, sorting does not matter
  3. sorting the output only has any bearing on the order of messages output by the inspector
  4. thus, sorting should be done JIT, which would be JUST BEFORE the formatter gets the data
  5. and this should happen in the CLI

transformers should accept config from rc files

This is a bug (I think). It looks like we're pulling the wrong data out of the config files. You should be able to set e.g., pretty: true in an RC file and have that reflected when running on CLI

rename project to report-toolkit

We may be able to rename this project back at some point (assuming future approval), but for now, it must be report-toolkit before it goes public.

i18n

Internationalization for strings

Documentation & HOWTO requests

Documentation needs/wants:

  • Provide TypeScript definitions
  • Provide user API documentation
  • Provide plugin author API documentation
  • Provide configuration documentation
  • Provide HOWTOs:
    • Redact a report running on Cloud Provider X
    • Build a Rule
    • Run as a service
    • Use in browser

Some of these may be absolutely essential, and some are nice-to-have, but there's a list.

distill options passed into transformers

Currently, we're sending whole gobs of configuration to transformers when we don't need to. Each transformer should probably define the options that it expects (e.g. via a schema like Rules support), and we can use that to pick the various useful options.

Configuration can be passed via:

  1. Command-line flags (if supported)
  2. Top-level via RC file
  3. Command-specific via RC file
  4. Transform-specific via RC file

Furthermore, default options should cascade within a transformer chain. If an option defines e.g., fields, and the user has not, this setting should pass to the next transformer(s) in the chain as long as those transformers accept the configuration. The target transformer should prefer the config sent from the previous transformer and treat it like it was user-defined.

need a Config class

The way we pull command-specific configuration out of the config is tedious. a Config class with a helper method or two would make this easier to digest.

also, it could help define the (post-normalization) interface.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.