-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
Ability to extend Logger class. #1902
Comments
That's a very good idea. I am currently trying to do the same :) |
I found a not pretty solution ... import winston from "winston"
// @ts-ignore
class Logger extends (createLogger as winston.Logger) {
constructor(config: winston.LoggerOptions) {
super(config)
}
}
console.log(new Logger({})) That works for me, but I don't like use @ts-ignore and extends by a function. |
Unfortunately this breaks |
Another non-elegant solution that doesn't break .child(), used in my project: https://github.com/wesamjabali/nest-graphql-starter/blob/main/src/core/logger/logger.service.ts The important bits: import {
child,
createLogger,
format,
LeveledLogMethod,
Logger,
transports,
} from 'winston';
export class LoggerService {
private coreLogger: Logger;
isErrorEnabled: () => boolean;
isWarnEnabled: () => boolean;
isInfoEnabled: () => boolean;
isVerboseEnabled: () => boolean;
isDebugEnabled: () => boolean;
isSillyEnabled: () => boolean;
error: LeveledLogMethod;
warn: LeveledLogMethod;
info: LeveledLogMethod;
http: LeveledLogMethod;
verbose: LeveledLogMethod;
debug: LeveledLogMethod;
silly: LeveledLogMethod;
child: typeof child;
log = (...message: string[]) => {
this.coreLogger.defaultMeta = { service: message?.[1] ?? DEFAULT_SERVICE };
this.coreLogger.log(LOG_LEVEL, message?.[0] ?? '');
};
constructor() {
const winstonLogger = createLogger({...});
Object.setPrototypeOf(this, Object.getPrototypeOf(winstonLogger));
this.coreLogger = winstonLogger;
for (const key of Object.keys(winstonLogger)) {
this[key] = winstonLogger[key];
}
} Hope this helps someone. Please let me know if you have any questions. You have to assign log to the corelogger's info otherwise it'll infinite loop. |
I'm just reaching for it deep into the package import { transports, format, Logger } from 'winston';
//@ts-expect-error Winston doesn't export the Logger class but it's easy to reach for it. See https://github.com/winstonjs/winston/issues/2170
import HiddenLogger from 'winston/lib/winston/logger';
// Easy to reach for, but hard to type.
const LoggerClass = HiddenLogger as typeof Logger; |
Any plans to implement this? |
+1 |
#2181 has failing tests and even I don't seem to have permissions to re-run them. |
See also #2170 |
@wbt, is there anyone you can contact on the core team to get this fixed? It looks like it has been sitting here for a few years now. |
There's also been no funding for a few years now for anybody on the core team to author or review updates and extensions, so that's not a big surprise. |
Is winston dying then?On May 27, 2023, at 16:13, wbt ***@***.***> wrote:
There's also been no funding for a few years now for anybody on the core team to author or review updates and extensions, so that's not a big surprise.
—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you commented.Message ID: ***@***.***>
|
It's in a state of being maintained, but not actively expanding/growing. Folks who find it useful could still contribute skilled effort and/or funding to pay for it; some occasionally do make the first type of contribution. |
This should be solved via #2181 and will go out in the next release |
Any hint at when the next release will be? |
Published in 3.10.0 |
@Faithfinder Any chance you would be able to investigate and possibly address @marc-wilson 's issue here? |
I'm not really ready to become a maintainer =P
Though if I were serious about that, I'd argue to drop this feature anyway. Correctly defining types for properties/methods dynamically derived from options is some typescript wizardry. Probably possible, but I'd argue that not worth it. |
Haha, you might already be the number one expert on extending the Agree on |
Nonono, it's not. The methods don't exist on the class itself. Typescript just falsely says that they're there. This is the specific line that does it. winston/lib/winston/create-logger.js Line 53 in 19ac9d8
|
Fair enough, @Faithfinder I would suggest (respectfully) reopening this issue since the PR doesn't address what's called out in the issue; therefore, the feature/issue is still outstanding. I can certainly still make things work since the fix @Faithfinder did addressed a big portion of the root issue. I would just rather be able to do The last few comments does bring me back to this comment, though:
|
It's easy enough to do this manually with the added benefit of additional typesafety - you can define class CustomLogger extends Logger {
/* other stuff */
info = (message: string, meta: any): void => {
this.log({ level: 'info', message, ...meta });
};
}
Oh, but it's always been true. If you pass your levels in manually, the types don't know about it. Even if you don't - createLogger().emerg('message') currently will pass typecheck, but fail at runtime. I consider extending the Logger class a "secret advanced" feature, to use at your own risk - hence why I didn't update any docs in my PR. Changing the type definitions would be very much a breaking change for many people. You could get creative with Typescript instead and define special type for |
There is indeed no funding but occasionally the maintainers are still able to do reviews :) For new features and improvements there is more reliance on the community though. That being said, I reopened the issue per the above discussion, but if somebody wants to make a PR that actually adds support for the leveled log methods for extended classes, I’d be more than happy to review and do a release. Let me know what sounds like the best option for you. |
Can someone quickly jot an example of how this extension now works? The createLogger will create the derived Winston Logger, right? Not quite sure how to get an extended logger to get built in the right spot. We need custom metadata on a per log call and so being able to construct child loggers that have an overridden log call is what we're trying to do. So createLogger.child() returning a custom instance. Or, just to hack wrappers to make it all work. I've been trying to just extend Logger to override the log method (since that is what I want to tweak)...and then provide my own createLogger that just takes a base logger and returns a child (which would be of this new type). I can't get the TypeScript to work for the log method signature.
|
What is the problem?
I am trying to extend winston logger with custom methods on typescript. Currently it can only be done via
as any
and assigning properties to the object manually. Moreover, methods likeLogger#child
require to be improved.Here is how it looks like:
What's the feature?
Ideally, I want to be able to extend
Logger
in a pretty OOP way without manual property assignment manipulations like:Is it possible to add such a functionality and ensure typescript is supported?
What problem is the feature intended to solve?
Make winston logger more extensible in a clear way that is common for OOP language.
Is the absence of this feature blocking you or your team? If so, how?
It is not a blockers as there are hacks to achieve that.
Is this feature similar to an existing feature in another tool?
Yes, this feature is common feature in any OOP friendly logger where you can just use inheritance as a pattern.
It is very unusual that making
Logger
is done through a factory method but not a constructor. Most loggers just expose aLogger
class to you like so: https://ruby-doc.org/stdlib-2.4.0/libdoc/logger/rdoc/Logger.htmlIs this a feature you're prepared to implement, with support from us?
Yes.
The text was updated successfully, but these errors were encountered: