muter
A node package to mute and/or capture console or other loggers' logs
Basic usage
Muter is a factory class generally taking two main arguments, the logger and the spied-on method name, plus an optional one used to help reformat the captured messages if desired.
Basic muting
Using Muter can be as simple as writing the few lines:
; const muter = console 'log'; // Sets a Muter on console.logmuter; // The Muter starts muting console.log console; // console.log prints nothing const logs = muter; // Returns 'Lorem ipsum\n' muter; // The Muter stops muting console.log
Therefore a Muter does not only mute a specific logging method but it also always captures what the muted method is expected to print.
Basic capturing
Muter can be used to capture seamlessly what a specific method of a logger is expected to print, that is to say without muting it. To do that, just call 'capture' instead of 'mute':
; const muter = console 'log'; // Sets a Muter on console.logmuter; // The Muter starts capturing console.log console; // console.log prints as usual const logs = muter; // Returns 'Lorem ipsum\n' muter; // The Muter stops capturing console.log
Using options
The messages captured by a Muter can be altered:
; const muter = console 'log' color: 'magenta' { return args; } endString: ' ▪▪▪'; // Sets a Muter on console.log with special formatting optionsmuter; // The Muter starts muting console.log console; // console.log prints nothing const logs = muter; // Returns 'Lorem • ipsum ▪▪▪' in magenta muter; // The Muter stops muting console.log
But a Muter won't usually interfere with what is printed by the logging method when it is only captured and not muted altogether:
; const muter = console 'log' color: 'magenta' { return args; } endString: ' ▪▪▪'; // Sets a Muter on console.log with special formatting optionsmuter; // The Muter starts capturing console.log console; // console.log prints as usual with no special formatting, that is to say 'Lorem ipsum\n' const logs = muter; // Returns 'Lorem • ipsum ▪▪▪' in magenta muter; // The Muter stops capturing console.log
Available options
color
: Allows to change the output color. If not provided, text will be printed in default stdout/stderr color (most likely white on black or black on white). Colors are as defined by the chalk module.format
: Allows to reformat the arguments with which logger[methodName] is called. format is a function taking the arguments passed to the logging method and returning a string. See Using options for an example.endString
: Helps change how the output string resulting from the call to logger[methodName] is terminated. It is simply '' or '\n' by default, but could be more sophisticated. See Using options as an example.logger
: Not used when calling factory, but by methods 'getLogs' and 'flush'. When the Muter references several pairs (logger, methodName), this option in conjunction with the following one allows to precise which logging channel to access. See Coordinated muting/capturing for an example.method
: Not used when calling factory, but by methods 'getLogs' and 'flush'. When the Muter references several pairs (logger, methodName), this option in conjunction with the previous one allows to precise which logging channel to access. See Coordinated muting/capturing for an example.
Overriding options
The options that a Muter was set with can be overridden when recovering the logged messages:
; const muter = console 'log' color: 'magenta' { return args; } endString: ' ▪▪▪'; // Sets a Muter on console.log with special formatting optionsmuter; // The Muter starts muting console.log console; // console.log prints nothing var logs = muter; // Returns 'Lorem • ipsum ▪▪▪' in magenta logs = muter; // Returns 'Lorem • ipsum ▪' in cyan logs = muter; // Returns 'Lorem ••• ipsum ▪▪▪' in magenta muter; // The Muter stops muting console.log
Clearing
To clear a Muter, that is to say to both forget the captured logs and stop muting/capturing, you just call 'unmute' or 'uncapture'.
; const muter = console 'log'; // Sets a Muter on console.logmuter; // The Muter starts muting console.log console; // console.log prints nothing var logs = muter; // Returns 'Lorem ipsum\n' muter; // The Muter stops muting console.log logs = muter; // Returns nothing console; // console.log prints as expected logs = muter; // Returns nothing
Using several Muters in parallel
Distinct Muters
Muters can be used in parallel. They can't interfere with one another as long as they were not set with the same pair (logger, methodName).
In other words, two pairs can share the same logger, as in the following example:
; const logMuter = console 'log'; // Sets a Muter on console.logconst errorMuter = console 'error'; // Sets a Muter on console.error logMuter; // logMuter starts muting console.logerrorMuter; // errorMuter starts muting console.error console; // console.log prints nothingconsole; // console.error prints nothingconsole; // console.error prints nothingconsole; // console.log prints nothing const logMessage = logMuter; // Returns 'Lorem\nsit\n'const errorMessage = errorMuter; // Returns 'ipsum\ndolor\n' logMuter; // logMuter stops muting console.logerrorMuter; // errorMuter stops muting console.error
Or they can share the same logging method, as in:
; const stdoutWrite = processstdout 'write'; // Sets a Muter on process.stdout.writeconst stderrWrite = processstderr 'write'; // Sets a Muter on process.stderr.write processstdoutwrite === processstderrwrite; // true stdoutWrite; // stdoutWrite starts muting process.stdout.writestderrWrite; // stderrWrite starts muting process.stderr.write processstdoutwrite === processstderrwrite; // false processstdout; // process.stdout.write prints nothingprocessstderr; // process.stderr.write prints nothingprocessstderr; // process.stderr.write prints nothingprocessstdout; // process.stdout.write prints nothing const outMessage = stdoutWrite; // Returns 'Loremsit'const errMessage = stderrWrite; // Returns 'ipsumdolor' stdoutWrite; // stdoutWrite stops muting process.stdout.writestderrWrite; // stderrWrite stops muting process.stderr.write
Of course, if two Muters share neither logger nor method, they'll a fortiori work alongside seamlessly.
Related Muters
Internally, Muters are singletons. They have a one-to-one correspondence to pairs (logger, methodName), as those are generally global anyway.
So the first time you set a Muter by calling the factory, it will create a Muter object. Any other time you call the factory with the same pair (logger, methodName), it will return that object (pure call) or a wrapper around it (call with a third options argument).
The advantage is that you can use the same Muter with different options. Muting one single wrapper will mute the logging method, but all wrappers will have to be unmuted to unmute that logging method. Moreover each wrapper captures the output from the moment it is muted and forgets everything from the moment it is unmuted. They have therefore different logging histories, and formatted differently.
But the master singleton returned by the factory called with no options keeps track of everything from the first muting to the last unmuting. That full history has no special custom format.
; const log1 = console 'log' color: 'blue'; // Sets a Muter on console.log; log1 is wrapper around the actual Muterconst log2 = console 'log' color: 'red'; // Associates another wrapper with different options to the same Muterconst log = console 'log'; // The actual Muter, with no special options log1; // log1 starts muting console.log console; // console.log prints nothingconsole; // console.log prints nothing var logMessage = log; // Returns 'Lorem\nipsum\n' in default colorvar logMessage1 = log1; // Returns 'Lorem\nipsum\n' in bluevar logMessage2 = log2; // Returns nothing log2; // log2 starts muting too console; // console.log prints nothing logMessage = log; // Returns 'Lorem\nipsum\ndolor\n' in default colorlogMessage1 = log1; // Returns 'Lorem\nipsum\ndolor\n' in bluelogMessage2 = log2; // Returns 'dolor\n' in red log1; // log1 stops muting console.log console; // console.log prints nothing because log2 is still muting logMessage = log; // Returns 'Lorem\nipsum\ndolor\nsit\n' in default colorlogMessage1 = log1; // Returns nothinglogMessage2 = log2; // Returns 'dolor\nsit\n' in red log2; // log2 stops muting console.log, which is fully unmuted console; // console.log prints 'amet' logMessage = log; // Returns nothinglogMessage1 = log1; // Returns nothinglogMessage2 = log2; // Returns nothing
Overlapping Muters
Overlapping Muters are coordinated Muters (see Advanced usage) that share one or more (logger, methodName) pairs.
You have to take special care when sharing logging methods across Muters as mismatch may appear when muting with one and unmuting with the other.
; const muter1 = console 'log' console 'warn'; // Sets a Muter on console.log and console.warn const muter2 = console 'warn' console 'error'; // Shares the Muter on console.warn and sets a Muter on console.error muter1; // muter1 mutes console.log and console.warn console; // console.log prints nothingconsole; // console.warn prints nothingconsole; // console.error prints as expected muter1; // Returns 'Lorem ipsum\ndolor\n'muter2; // Returns nothing muter2; // muter2 mutes console.error and starts recording console.warn muter2; // Returns ''muter2; // Returns '' because no history yet for console.warn since the time of mutingmuter1: // Returns 'dolor\n'; muter1; // Unmutes console.log but not console.warn (still muted by muter2), now being in an inconsistent statemuter2; // Unmutes console.warn and console.error, putting back muter1 in a consistent state
Advanced usage
Muters can be used in parallel as in Using several Muters in parallel, but they actually can be coordinated, that is to say that their states can be changed simultaneously without having to micromanage them.
A special construct is provided to achieve this, using the same factory interface, but instead of calling it with a triplet (logger, methodName, options), you call it with a series of array arguments in a row, each containing a logger reference, a method name and optionally the options object.
Coordinated muting/capturing
Using the Muter factory with a series of array arguments, we can set up basic coordination between Muters. For example we can mute and unmute several logging methods simultaneously:
; const muter = console 'log' console 'warn' console 'error'; // Sets a Muter on console.log, console.warn and console.error muter; // The Muter mutes simultaneously console.log, console.warn and console.error console; // console.log prints nothingconsole; // console.warn prints nothingconsole; // console.log prints nothingconsole; // console.error prints nothingconsole; // console.log prints nothing const logMessage = muter; // Returns 'Lorem\ndolor\namet\n'const warnMessage = muter; // Returns 'ipsum\n'const errorMessage = muter; // Returns 'sit\n'const message = muter; // Returns 'Lorem\nipsum\ndolor\nsit\namet\n' muter; // The Muter unmutes simultaneously console.log, console.warn and console.error
Coordinated capturing is pretty much the same, by calling 'capture' instead of 'mute' and 'uncapture' instead of 'unmute'.
Printing
With 'getLogs', you can return whatever was logged from muting to unmuting. But you can also print it on screen with method 'print'.
; const muter = console 'log'; // Sets a Muter on console.logmuter; // The Muter starts muting console.log console; // console.log prints nothing muter; // Prints 'Lorem ipsum\n' console; // console.log prints nothing muter; // Prints 'Lorem ipsum\ndolor sit amet\n'muter; // Prints 'Lorem ipsum\n'muter; // Prints 'dolor sit amet\n' muter; // The Muter stops muting console.log
Flushing
First you 'mute'/'capture', last you 'unmute'/'uncapture'. Inbetween, you log stuff and if you want, you access the log history with 'getLogs'. But the log history is whatever was logged from muting to unmuting. You may want to get it by chunks, especially if you access it several times before unmuting. But you can also 'flush' the logs. Calling that method doesn't affect the state of the Muter, but it prints the current history before clearing it.
; const muter = console 'log'; // Sets a Muter on console.logmuter; // The Muter starts muting console.log console; // console.log prints nothing muter; // Prints 'Lorem ipsum\n'muter; // Prints nothing console; // console.log prints nothing muter; // Prints 'dolor sit amet\n'muter; // Prints nothing muter; // The Muter stops muting console.log
Forgetting
Method 'forget' flushes without printing on screen.
; const muter = console 'log'; // Sets a Muter on console.logmuter; // The Muter starts muting console.log console; // console.log prints nothing var logs = muter; // Returns 'Lorem ipsum\n'muter; // Forgets historylogs = muter; // Returns '' console; // console.log prints nothing logs = muter; // Returns 'dolor sit amet\n'muter; // Forgets historylogs = muter; // Returns '' muter; // The Muter stops muting console.log
CAVEAT
Side-effects
Muting or capturing logs can have unwanted repercutions throughout your running process as, most of the time, standard logging functions such as console.log
or process.stdout.write
are temporarily overridden.
If you forget to unmute your Muter whenever you don't need it anymore, or if you encounter an exception from which your process recovers without unmuting, you will most likely get plagued with random incomplete logging messages.
'muted' and 'captured' convenience wrappers
In order to mitigate those side-effects, two function wrappers are provided that will take care of cleaning up as soon as you're done with muting or if an unhandled exception is thrown: muted
and captured
.
; const muter = console; const func = { console; console; console; return muter;}; const safelyMutedFunc = ;const safelyCapturedFunc = ; const res1 = ; // Prints nothing: muter is mutingconst res2 = ; // Prints 'lorem\nipsum\ndolor\n'; res1 === res2; // trueres2 === 'lorem\nipsum\ndolor\n'; // true: muter was capturingres2 === muter; // false: muter is no longer muting nor capturing try ; // Prints nothing, throws error catche console; // Prints error as expected try ; // Prints 'lorem', throws error catche console; // Prints error as expected
Miscellaneous
Format strings
Muter supports the same format strings as console in Node.js as it utilizes util.format from util module under the hood.
; const muter = console 'log'; // Sets a Muter on console.log muter; // Mutes console.log for let i = 1; i < 4; i++ console; // console.log prints nothing const logs = muter; // Returns '1) message1\n2) message2\n3) message3\n' muter; // Unmutes console.log
But if you specify a custom formatter as an option, it's your responsability to handle the special formatting strings.
Handling hidden logging methods
Some fancy loggers print on interleaved channels. To mute such loggers, you need first to identify all those channels and then set a coordinating Muter on them (see Advanced usage), as in the following example:
; { console; console; console;} // A custom logging function printing on interleaved console.info and console.log const muter = console 'info' console 'log'; // Sets a Muter on console.info and console.log muter; // Mutes console.info and console.log, therefore muting the custom logging function 'log' ; // Prints nothing; // Prints nothing const logs = muter; // Returns '>>>>\nLorem ipsum\n<<<<\n>>>>\ndolor sit amet\n<<<<\n' muter; // Unmutes console.info and console.log, therefore unmuting the custom logging function 'log'
gulp-util logger
gulp-util 'log' method is such a fancy logger. The two interleaved channels are process.stdout.write and console.log. But you may use a special construct directly, see Special arguments.
Special arguments
As a convenience, you may call the Muter factory with special arguments to have common Muters be set.
; const muter1 = process; // Sets Muters on process.stdout.write and process.stderr.write, therefore allowing to silence the whole processconst muter2 = console; // Sets Muters on all four logging methods of console
Full API
Muter methods
new Muter(logger, methodName [, options])
: Muter is the default import of the 'muter' module. With no options, this construct returns a singleton associated with the pair (logger, methodName), able to mute/unmute it at will (see Basic muting). Options are explained in Using options. When options are set, the method returns a wrapper around the above singleton.Muter(Array(logger1, methodName1 [, options1]), Array(logger2, methodName2 [, options2])[, ...])
: This construct improves on the previous one, allowing to set coordinated Muters on several pairs (logger, methodName) (see Coordinated muting/capturing).mute()
: Mutes (and captures) all pairs (logger, methodName) referenced by the Muter. See Basic muting and Coordinated muting/capturing.unmute()
: Unmutes all pairs (logger, methodName) referenced by the Muter and resets logging history.capture()
: Captures all pairs (logger, methodName) referenced by the Muter. See Basic capturing and Coordinated muting/capturing.uncapture()
: Uncaptures all pairs (logger, methodName) referenced by the Muter and resets logging history.print([nth])
: Prints the whole logging history (no argument) or the nth logged message by one of the muted/captured pair (logger, methodName), see Printing.getLogs([options])
: Returns the whole logging history since last muting/capturing/flushing. options override those set on the pair (logger, methodName) on creation (see Overriding options).flush([options])
: Like 'getLogs([options])', returns the whole logging history, but also both prints it and resets it, see Flushing.forget()
: Returns and resets the logging history, but don't print it, see Forgetting.
Utilities
muted(muter, func)
: Returns a wrapper around functionfunc
that'll first mute the logging methods handled bymuter
, then runfunc
(that supposedly calls the aforementioned logging methods during its run) and finally unmute the logging methods, either upon returning or upon catching an exception. See 'muted' and 'captured' convenience wrappers for an example.captured(muter, func)
: Returns a wrapper around functionfunc
that'll first capture the logging methods handled bymuter
, then runfunc
(that supposedly calls the aforementioned logging methods during its run) and finally unmute the logging methods, either upon returning or upon catching an exception. See 'muted' and 'captured' convenience wrappers for an example.
License
muter is MIT licensed.
© 2016-2019 Jason Lenoble