README
node-error-report
This package is used as base for error parsing logic on node-vtex-api and vtex-toolbelt.
Install
$ yarn global add @vtex/node-error-report
API
The ErrorReportBase
is a wrapper for node errors that provides features like error serialization, sanitization and error parsing (in case of request errors, for example).
Instantiation
It has the following constructor arguments:
kind [required]
This is supposed to be an error code to make error identification on a logs backend easier.
originalError [required]
This is the originalError to be wrapped by the ErrorReportBase
- it will try to parse meaningful information on the error and add it to the parsedInfo
instance variable.
config [required]
Configures error serialization aspects:
- Max string size on each field.
- Max object depth.
message [optional]
ErrorReportBase
uses originalError.message
as default error message. This allows to override it.
details [optional]
This is a object with additional details on the error, can be used in cases like:
try {
content = readFileSync(filename)
} catch(err) {
new ErrorReportBase({
...,
details: {
filename
}
})
}
Note that this is useful because sometimes errors thrown by standard functions doesn't help us to pinpoint the issue.
Serialization
The serialization task is done by the toObject
method on ErrorReportBase
. It will:
- Remove circular references.
- Truncate strings bigger than
config.maxStringLength
. - Sanitize jwt tokens (the token identification logic right now is not that good).
Also, the toObject
will have error metadata, the details provided by whom instantiated the error, the original error stack, message and parsed info.
Error parsing
For now just axios request errors are parsed - some key information on the request are stripped out to a object (code).
Also it's possible to create parseable errors by implementing the ParseableError
interface, e.g.:
export class EventSourceError extends Error implements ParseableError {
public event: any
public eventSourceInfo: EventSourceInfo
constructor(event: any, eventSourceInfo: EventSourceInfo) {
super(`SSE error on endpoint ${eventSourceInfo.url}`)
this.eventSourceInfo = eventSourceInfo
this.event = { ...event }
}
public getDetailsObject() {
return {
event: this.event,
eventSourceInfo: this.eventSourceInfo,
}
}
}
When instantianting a ErrorReportBase
and providing an EventSourceError
object as the originalError
, the parseInfo
on ErrorReportBase
will be the content returned by getDetailsObject
.
Parsed info type guards
Some typescript type guards implemented are also exported:
isRequestInfo
: Checks if theparsedInfo
instance variable is the result of a request parsing.isInfraErrorData
: Checks if therequestInfo.response.data
is a VTEX IO infra error (these errors can be used to improve the error report).
Helpers
createErrorReportBaseArgs
This function abstracts away some instantiation logic, it allows the function user to optionally specify the kind
(if not specified a generic kind will be used - GenericError
or RequestError
) and abstracts away the config
creation. The configs will be provided by:
maxStringLength: ErrorReportBase.MAX_ERROR_STRING_LENGTH
maxSerializationDepth: ErrorReportBase.MAX_SERIALIZATION_DEPTH
The ErrorReportBase
allow these default values to be changed, e.g.:
ErrorReportBase.MAX_ERROR_STRING_LENGTH = 2048
Usage example
The ErrorReportBase
class is supposed to be extended with functions for reporting the error to a log/tracing backend, for example:
export class ErrorReport extends ErrorReportBase {
public static create(args: ErrorReportCreateArgs) {
return new ErrorReport(createErrorReportBaseArgs(args))
}
constructor(args: ErrorReportBaseConstructorArgs) {
const { workspace, account } = SessionManager.getSingleton()
const env: ErrorEnv = {
account,
workspace,
toolbeltVersion: pkg.version,
nodeVersion: process.version,
platform: getPlatform(),
command: process.argv.slice(2).join(' '),
}
super({
...args,
details: {
...args.details,
env,
},
})
}
public sendToTelemetry() {
if (!this.isErrorReported()) {
TelemetryCollector.getCollector().registerError(this)
this.markErrorAsReported()
}
return this
}
}
The ErrorReportBase
class keeps track of the report state of the error, to avoid sending the same originalError
to the backend twice - that's the role of the methods isErrorReported
and markErrorAsReported
. These functions add metadata to the originalError
as well, so if the same originalError
is passed to another ErrorReportBase
instance, the report state will be maintained.
Metrics
ErrorReportBase
exposes the following metrics that can be reported to a metrics/logs backend and accessed via errorReporObj.metadata.metrics
:
instantiationTime
On its instantiation, the ErrorReportBase
class clones and sanitizes some fields from the arguments provided, for example:
- All info extracted from
RequestError
s are sanitized and cloned. - The
details
object is sanitized and cloned. This is done because later uses of these objects (or sub-objects) could be affected ifErrorReportBase
didn't cloned them and changed anything (for example, it could sanitize theAuthorization
header, then later uses of the same request config would end up with auth errors).
But this may be costly (who knows?). Because of this, ErrorReportBase
exposes the instantiationTime
metric.