pimterry / loglevel

:ledger: Minimal lightweight logging for JavaScript, adding reliable log level methods to wrap any available console.log methods
MIT License
2.62k stars 157 forks source link

WIP: Multiple logger support #81

Closed Mr0grog closed 9 years ago

Mr0grog commented 9 years ago

This is a simplistic implementation of #68 with minimal changes to the actual codebase (it looks a bit bigger than it really is because many methods moved into the logger constructor).

For the most part, all this ultimately does is add a method named getLogger(name) to the library. That method returns a new logger with the given name, or, if it’s already been called with that name, returns the previously created logger. The library itself is actually just an instance of one of these loggers, but it has the getLogger() and noConflict() methods sprinkled on top.

There are a couple ugly things in here, mostly pertaining to the discussion of inheritance: https://github.com/pimterry/loglevel/issues/68#issuecomment-120677667

pimterry commented 9 years ago

Great work, thanks for chasing this! I think overall this approach is very good. I've put a couple of comments inline on specific tweaks, and there's a couple of wider things:

Mr0grog commented 9 years ago

Ok, I spent a little time this afternoon cleaning up the tests, adding docs, and fixing methodFactory so it gets the right args (forgot about that last time around).

I haven’t worked on better solutions to the private-but-shared-across-instances issue with enableLoggingWhenConsoleArrives et al. However, some thoughts:

Maybe that should just take a logger argument too, but that's not something most plugins should need to implement a method factory

I’m skeptical that a third-party plug-in shouldn’t be capable of doing something the built-in one can. Besides, the current implementation already sends methodFactory the logger—just as this rather than an argument.

That said, I get the idea that the API should hopefully push developers towards doing the “right” thing. Maybe one approach would be to send the methodFactory a function that resets the logging methods (i.e. a version of replaceLoggingMethods that takes no arguments) and not be given the actual logger instance as this. That severely constrains what a plug-in can do, while still enabling current functionality. But maybe all this is better discussed in relation to v2 or adding setMethodFactory(). Is there an issue for that?

pimterry commented 9 years ago

I’m skeptical that a third-party plug-in shouldn’t be capable of doing something the built-in one can. Besides, the current implementation already sends methodFactory the logger—just as this rather than an argument. That said, I get the idea that the API should hopefully push developers towards doing the “right” thing.

Mm, my concern isn't really so much what's possible, but what the API encourages people to do. If you only need the logger in strange and wonderful cases, I'd rather not pass it as an explicit argument. Providing it only as the context feels less visible and suggestive, although I realise that's a pretty fluffy argument.

But maybe all this is better discussed in relation to v2 or adding setMethodFactory(). Is there an issue for that?

There is now: #82.

I was thinking this wouldn't make much difference, but actually I think it really does. A big part of this current problem is that the current method factory API is quite unfriendly to this, and we're exposing the default factory, so we have to be careful to make that usable. If we're breaking the API anyway we can stop doing both of those though, so that writing a plugin looks more like:

log.wrapLogMethods(function (defaultLogMethod, methodName, loggerName) {
  return function (message) {
    defaultLogMethod("Newsflash: ", message);
  };
});

No need to read the current log factory (which is good, because that field being exposed is part of why I want to change this), and nobody ever sees the default method factory at all, only its output.

That's all great for this, as it turns out, because that means we can split the internal representation. Rather than just having a log.methodFactory property for everything, we can have a private methodFactory function inside the Logger (lexically inside, so it can closure in self like every other private function), plus a separate customMethodWrapper field, which is undefined unless set with .wrapLogMethods, and which can be safely copied between instances.

Some of those details are still a bit vague, but I'm reasonably confident that this means we can clean this up easily once that's added. Given that, lets just ignore this for now.

Other than things the next change will fix I think this looks great, so I'm going to merge it now and then get started on the improved plugin API. Any thoughts you have on all this would be very interesting though, over on #82.

Thanks!

davetayls commented 9 years ago

looking forward to this one :+1: