-
-
Notifications
You must be signed in to change notification settings - Fork 66
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Bug: BaseLogger breaks if Class of logged error has > 1 required constructor arguments #227
Comments
Workaround: Go back to 4.7.4. This was introduced by a5a0ac2 |
Thank you for reporting. This method is used to clone the error object in order safely manipulate the cloned one (especially for masking secrets) without changing the original one. private _cloneError<T extends Error>(error: T): T {
const ErrorConstructor = error.constructor as new (...args: any[]) => T;
const errorProperties = Object.getOwnPropertyNames(error);
const errorArgs = errorProperties.map((propName) => error[propName]);
const newError = new ErrorConstructor(...errorArgs);
Object.assign(newError, error);
for (const propName of errorProperties) {
const propDesc = Object.getOwnPropertyDescriptor(newError, propName);
if (propDesc) {
propDesc.writable = true;
Object.defineProperty(newError, propName, propDesc);
}
}
return newError;
} |
Hey, thanks for the reply. The new version assumes, that object properties map one-on-one and ordered, to constructor arguments (some kind of dynamic copy constructor) This is a heuristic, that could work in my case or for the libraries I use. But in general, I think, it's not valid to assume all subclasses of For my own code, I could follow this pattern, but I cannot control what others throw. I'm using my logger (as most do) to log all kind of unexpected errors, too. Anyway, in my opinion, nothing I pass to tslog should crash tslog (same as console.log) Beyond, I don't think there's a way to clone an error by invoking its constructor, without knowing what the constructor was called with initially (which we don't). Cloning objects, and especially class instances is a non-trivial issue that is not natively supported by JS, as far as I know: There's structuredClone, but it's only supported since Node 17, so not backward compatible. Also, it does not clone the prototype chain ( |
That's exactly the problem here. On the one hand we want to offer secret masking, which in my opinion is essential for logging, on the other hand we don't want to manipulate the original object and therefore need a copy of it and there is no official way of doing so for the error object. Have you any thoughts on how to solve this? |
After reading a bit up on this, I think there's no way to reliably invoke a constructor without static knowledge about it (for reference: https://stackoverflow.com/a/16025595/2465945). // This contrived error class would break the dynamic constructor invocation from above
// I'm 100% sure, there's something like this in the wild
class ErrorWithRequiredSecond extends Error {
private x: { [key: string]: any };
constructor(message: string, json: string) {
super(message);
this.message = message;
this.x = JSON.parse(json);
}
} If we don't have to uphold the // We have to use the normal Error constructor or some internal error class
const clonedError = new Error(error.message);
// will print the correct name
clonedError.name = error.name;
// or clonedError.prototype = error.prototype, but not sure what implications of this are
// stack is not enumerable, so we need to move it manually, Object.assign won't do
// Some libraries also remove "stack" in production, so we can't be sure it exists at all
// but if so, we don't want to log the stack of the clone either
clonedError.stack = error.stack || "";
Object.assign(clonedError, error);
const errorProperties = Object.getOwnPropertyNames(error);
for (const propName of errorProperties) {
// .... as above In this case, I don't think we can have our cake and eat it, too. The cloned error would look like the original with respect to logging stuff. If consumers need |
For me it breaks for typeorm
|
"Resolves" the following issue: fullstack-build/tslog#227
Please check |
Describe the bug
This line assumes that an error constructor has only one required parameter:
tslog/src/BaseLogger.ts
Line 280 in 28ef27a
If that is not the case, this code breaks the invoked error constructor.
To Reproduce
Expected behavior
I don't know what
_cloneError
is actually doing, but it should respect error constructors that have multiple required parameters, especially if I don't control these. For example the Prisma ORM throws errors with a second required parameter.Node.js Version
v16.18.1
The text was updated successfully, but these errors were encountered: