How many times did you write logger.info('ServiceName.methodName.') and logger.info('ServiceName.methodName -> done.') for each and every method of your service you wanted to log? Would you like it to be automated and has the same constant signature across your whole app? If that's so, we're very much alike, we have suffered the same pain too many times, and now we could finally try to resolve it. Together. Ladies and gentlemen, let me introduce… class-logger! Engineers are often perfectionists. Perfectionists to the extreme. We like neat abstractions. We like clean code. We see beauty in artificial languages other people cannot even read. We like manufacturing small digital universes, living by the rules we set. We like all of that, probably, because we're very lazy. No, we're not afraid of work, but we hate doing any work that can be automated. Having written couple thousands of lines of logging code only, we usually come up with certain patterns, standardizing what we want to log. Yet we still have to apply those pattern manually. So the core idea of class-logger is to provide a declarative highly-configurable standardized way to log messages before and after the execution of a class method. Let's hit the ground running and see what the actual code looks like. This service is going to log three times: In words of code: Live demo. What else could we log? Here's the complete list of events: So far so good, but we've been promised "customizable", right? So how can we tweak it? class-logger provides three layers of hierarchical config: At every method call, all three of them are evaluated and merged together from top to bottom. There's some sane default global config, so you can use the library without any configuration at all. It's the app-wide config. Can be set with setConfig call. It has an effect over every method of your class. It could override the global config. It affects only the method itself. Overrides class config and, therefore, global config. Live demo Well, we've learned how to alter the defaults, yet it wouldn't hurt to cover what there is to configure, huh? Configuration object has these properties: It's a function that does the actual logging of the final formatted message. It's used to log these events: Default: console.log It's a function that does the actual logging of the final formatted error message. It's used to log this one and only event: Default: console.error It's an object with two methods: start and end. It formats logging data into the final string. start formats messages for these events: end formats messages for these events: Default: new ClassLoggerFormatterService() The configuration of what should be included in the message. It could be either a boolean or an object. If it's a boolean, it sets whether to include the list of arguments (remember that Args: [milk]?) into both, start (before construction and before method call) and end (after method call, error method call), messages. If it's an object, it should have two boolean properties: start and end. start includes/excludes the list of arguments for start messages, end does the same for end messages. Default: true A boolean flag setting whether to log class construction or not. Default: true Another boolean flag setting whether to include a return value of a method call or an error thrown by it. Remember Res: purr? If you set this flag to false there will be no Res: purr. Default: true Once again, either a boolean or an object.
If you enable it, a stringified representation of your class instance will be added to the logs. In other words, if your class instance has some properties, they will be converted to a JSON string and added to the log message. Not all properties will be added. class-logger follows this logic: Default: false So what if you like the overall idea, but would like your messages to look differently? You can take complete control over formatting passing your own custom formatter. You could write your own formatter from scratch. Totally. Yet we're not going to cover this option here (if you're really interested in that, address the "Formatting" section of the README). The fastest and, probably, easiest thing to do is to subclass a built-in default formatter — ClassLoggerFormatterService. ClassLoggerFormatterService has these protected methods, serving as building blocks of the final message: The start message consists of: The end message consists of: You can override any one of those building-block methods. Let's take a look at how we could add a timestamp. I'm not saying we should. pino, winston and many other loggers are capable of adding timestamps on their own. SO the example is purely educative. Live demo Please, don't forget to follow installation steps and get acquainted with requirements before you decide to use this library. Hopefully, you've found something useful for your project. Feel free to communicate your feedback to me! I most certainly appreciate any criticism and questions. Software Engineer