Closed jmcook1186 closed 4 months ago
Currently, I have attached a branch with a possible solution to this problem.
CLI
, Manifest
, Plugin
, etc.(severity)[scope]
<message here>
Some initial thoughts on this.
[!important] Hello
@narekhovhannisyan @jawache let's spike on this because I anticipate this blocking some other priority tasks such as https://github.com/Green-Software-Foundation/if/issues/337 and https://github.com/Green-Software-Foundation/if/issues/615. We need to determine:
Some of this might be covered by @narekhovhannisyan 's work detailed in comments above, but we need to understand where we are and get aligned on what specific outcomes we want to see.
Thanks @jmcook1186, the top level issue for all of this is this in my opinion: https://github.com/Green-Software-Foundation/if/issues/600 that's what I put in the Notion doc.
The intention of that issue was a broader discussion, based partly on on my personal challenges over the last few months trying to build manifest files and how our logging is lacking on many levels (not just the way we express errors in the console).
I'll put my thoughts on the top level ticket but I'd rather we have a broader conversation first, and then from that narrow into specific tasks like how we want exceptions to be logged.
Blocked as waiting for #600
needs a sign off after the call on tuesday next week
@narekhovhannisyan please review the AC to confirm it's clear / ready for dev + add a size
@narekhovhannisyan please see the above comment to get this issue moving to the next stage
@jmcook1186
Add documentation to if.greensoftware.foundation and plugin template repo explaining that plugin builders should raise errors using console.error({CLASS}:{message}) and that the classes are to be found in errors.ts int he template repo (identical to the same file in the IF repo).
Here it says that users should rise error via console.error. However, users should throw an error to raise instead of logging. So it means our logger should handle formatting instead of the end user which will simplify user experience.
moving strings.ts
will create difficulties for us and for the users since we have to create PRs every time to add error message or fix already existing one. At the moment only common types and error classes can be moved. We will see on the go what else we can move.
Sizing as L
ok so if I understand correctly, users throw new Error()
invoking one of our classes that they import from if-core
.
strings.ts
can stay in IF and not migrate to if-core
.
@jmcook1186 we can move global config validation as a utility to if-core. It's redundant and plugin developers should write the same structure again and again.
const validateGlobalConfig = () => {
if (!globalConfig) {
throw new GlobalConfigError(MISSING_GLOBAL_CONFIG);
}
const globalConfigSchema = z.object({
coefficient: z.number(),
'input-parameter': z.string().min(1),
'output-parameter': z.string().min(1),
});
return validate<z.infer<typeof globalConfigSchema>>(
globalConfigSchema,
globalConfig
);
};
We can convert it into function and make it utility.
@jmcook1186 If plugins return an error that we don’t recognize or can’t parse, we should fail loudly in the console and exit.
What kind of logging do we want for this? currently we have logging which forwards user to our issue template.
This should just refer to users using an error class that we don't already support - in which case we need to include an error class in if-core
that covers unknown error classes!
e.g. error UnsupportedErrorClass: plugin threw error class: <errorClass> that is not recognised by Impact Framework
Maybe we need a generic error class to act as a catch-all that we apply whenever a plugin just uses raw console.log()
, e.g. it gets parsed as
Unspecified Error: The user has not provided an IF error class. The message was: <error message>
But if a user does provide an error class but it's not one of our supported ones, it throws an UnsupportedErrorClass
exception.
wyt?
PR of First part will be ready this afternoon There will be at leat 4 PRs in total This feels like going over L estimate
@jmcook1186 I have another suggestion which is simplier in this case. At the moment we already have a handler for errors, and it already checks if error classes that are included in our list. If the error class is unknown, then logs it with the reference to issue. We can tune that behavior to error UnsupportedErrorClass: plugin threw error class: <errorClass> that is not recognized by Impact Framework
. WDYT?
@narekhovhannisyan ok that seems good. What happens if the plugin builder provides no error class and just uses raw console.x
?
@jmcook1186 we should ignore it in our error handling layer. It will be caught by logging handler
@narekhovhannisyan ok, so it would only be printed to the console if --debug
is raised?
let me check
with debug flag it logs like this
INFO: 2024-06-11T09:35:37.530Z: sum: test log
without debug flag
test log
ok that seems fine. I guess what we're saying to plugin builders is that if you want to give your users the best UX, tight integration to IF and access to docs and debugging support then you have to use our error handlers, and we'll make that as easy as possible, but if you don't we won't break your ability to emit messages to the console. That makes sense to me.
@narekhovhannisyan
@jmcook1186 agree. So we are limiting the use of error classes that are not supported from our side. Yeah?
@narekhovhannisyan to prepare a break down of the topics and how it could be divided between all who can help
@jmcook1186 can you please help me with this one?
the README for each builtin includes a comprehensive list of the error messages the builtin can emit, with reasons and remedies linking to the appropriate docs.
Related issue #602 for @jmcook1186
Sub of #655
What
Define and implement standards for error reporting that enable plugin developers to report clear, actionable information to users and make use of our IF logging protocols.
Why
As a user I want to be able to diagnose problems with IF from the error messages. As a developer I want to work with the IF logger and emit error messages in a way that integrates well with IF.
Context
We want to emit error messages using a finite set of predefined error classes so that we can provide specific documentation and advice to users in our documentation about the behaviours that lead to errors of each class and common remedies.
In our logging upgrade (#600 ) we are likely to implement a simple rerouting of console.x methods from plugins to the IF logger so that they can be reformatted and responsive to IF CLI flags. We can also use this same flow to improve how IF handles errors emitted from plugins.
First, we encourage plugin builders to use
console.error()
for their error messages andconsole.warn
for warnings. IF then routes these to the Winston logger and prepends the name of the plugin that raised the error. The logger can also do some validation, for example we want error messages to come in the form:CLASS: message
where the class is one of the predefined classes we publish in an
if-core
package. That package should include ourerrors.ts
andstrings.ts
files so that they can be imported by plugin developers and we can refine and add to the files by creating new releases developers can install, rather than trying to convince plugin developers to copy files manually.All a plugin builder need do is import the error classes they need from
if-core
and use console.error. Our IF logger handles everything else.So, the actual actions to satisfy this criterion are to:
if-core
containing common types and assets needed by plugin buildersif-core
as a dependency to the template repositoryEnhancing the error class list
Here's the list of error classes we currently use across our IF features and plugins
IF errors CliInputError ManifestValidationError ModuleInitializationError InvalidAggregationParamError InvalidGroupingError PluginCredentialError PluginInitalizationError WriteFileError AuthorizationError (plugin) APIRequestError (plugin) InputValidationError (plugin) UnsupportedValueError (plugin) ConfigValidationError (plugin) ReadFileError (plugin) WriteFileError (plugin) MakeDirectoryError (plugin)
Today we also maintain a set of messages in
if/src/config/strings.ts
. These are messages that can be emitted attached to one of the error classes. However, there are examples across theif
repository and elsewhere where some messages are defines instrings.ts
and others are written inline where the error is emitted, for example here are two errors emitted intime-sync.ts
:in this case the error is imported from
strings
in this case the error is defined inline
It would be better to have all error messages from IF features and builtins defined in
strings.ts
and avoid defining them inline wherever possible, as this approach makes them more reusable across IF and plugins and enables us to document them centrally.We should also consider deprecating the
errorBuilder
function everywhere across IF, as this is just a very simple function that we can do without but it makes it harder for plugins to conform to our error handling norms so we should remove it.So the actions to satisfy this criterion are:
strings.ts
SoW
[x] Update IF error handler to do validation on error messages to ensure a valid error class is invoked
[x] Check the list of error classes and identify any missing classes or classes we can remove.
[x] Confirm error classes are precise, unambiguous and understandable. Errors should be user-centric, not IF-centric, for example
InputValidationError
could be broken into more specific classes that describe what has actually failed, for exampleParameterIsInvalid
,RequiredParameterNotFound
etcWe can have some exceptions that we can try to automatically recover from, e.g.
RetryException
(the plugin hit some rate limit and wants us to retry in X seconds).[x] Migrate all custom errors in IF to
strings.ts
and eliminate any unnecessary replication[x] Deprecate error builder function everywhere across IF
[x] Add documentation to if.greensoftware.foundation and plugin template repo explaining that plugin builders should raise errors using
console.error({CLASS}:{message})
and that the classes are to be found inerrors.ts
int he template repo (identical to the same file in the IF repo)[x] Define the behaviours that cause errors of each class to arise, common examples, and possible remedies. This can all be added to if.greensoftware.foundation/reference/errors.
[x] Then we need to determine a strategy for how this list of error classes should be distributed to plugin builders and how plugin builders can integrate the IF error handling protocol (is documenting on IF site and adding our error builder to the template repository enough?)
[x] If plugins return an error that we don’t recognize or can’t parse, we should fail loudly in the console and exit.
Acceptance criteria
[x] error messages all use the with errors
THEN the error is always attached to a known error class
ErrorClass: error message
syntax and use a known, class fromerrors.ts
. GIVEN the suggested changes have been merged WHEN I run ie --manifest[x] the set of error types is documented on if.greensoftware.foundation GIVEN the documentation exists WHEN I navigate to if.greensoftware.foundation/reference/errors THEN I see the list of error types with a brief explanation of the kinds of behaviours that cause them to be emitted, with real examples from our codebase
[ ] the README for each builtin includes a comprehensive list of the error messages the builtin can emit, with reasons and remedies linking to the appropriate docs. GIVEN the suggested changes have been merged WHEN I visit if.greensoftware.foundation/reference/errors THEN I find a comprehensive list of the error types F can emit and understand when and why they are used.
[x] unit tests are updated where necessary GIVEN the suggested changes have been merged WHEN I run npx jest --coverage THEN I see a coverage report showing 100% coverage and 100% passing
[x] we have a repository,
if/core
and an associated npm package containing common assets needed by plugin builders, especiallyerrors.ts
andstrings.ts
. GIVEN this package exists WHEN I runnpm i @grnsft/if-core
THEN I receive the necessary files to use IF's error classes.[x]
if-core
is a dependency ofif-plugin-template
GIVEN the package exists and the dependency is added to the package.json inif-plugin-template
WHEN I downloadif-plugin-template
and runnpm i
THEN I seeif-core
in my local node-modules[x]
if-core
is a dependency ofif
, used as a source of errors (all errors should be imported from if-core) GIVEN the package exists and the dependency is added to the package.json inif
WHEN I downloadif
and runnpm i
THEN I seeif-core
in my local node-modules[x]
if-core
is a dependency ofif
, used as a source of plugin types (all types should be imported from if-core) GIVEN the package exists and the dependency is added to the package.json inif
WHEN I downloadif
and runnpm i
THEN I seeif-core
in my local node-modules