I use console.log in my JS files to trace the application.
The problem: logs are in production environment.
How can I remove lines like console.log from code?
P.S. Please do not advice text solutions like find + xargs + grep -v.
For my significant projects, I have my own logging function that internally uses console.log(), but there are no console.log() calls in my code except for the one place in this function. I can then enable or disable logging by changing one variable.
My function is actually a little more involved than this with options to put the output into places other than just the console, but conceptually, it looks like this:
// change this variable to false to globally turn off all logging
var myLoggingEnabled = true;
function myLog() {
if (myLoggingEnabled) {
if (window.console && console.log) {
console.log.apply(this, arguments);
}
}
}
You can then use code like this to log:
myLog(foo);
FYI, for deployed code compactness and performance optimization, I also have a minimization step that removes all calls to myLog() from my code. This is an optimization that I've chosen to take advantage of. Perhaps you could share why you wouldn't also consider this type of optimization.
Well, you can disable them with
console.log=function(){}
But the lines will be there unsless you delete them manually.
If you use Grunt you can add a task so as to remove/comment the console.log statements.
Therefore the console.log are no longer called.
https://www.npmjs.org/package/grunt-remove-logging-calls
Yeah, I had a similar situation, I posted about it here. http://bhavinsurela.com/naive-way-of-overriding-console-log/
This is the gist of the code.
var domainNames =["fiddle.jshell.net"]; // we replace this by our production domain.
var logger = {
force:false,
original:null,
log:function(obj)
{
var hostName = window.location.hostname;
if(domainNames.indexOf(hostName) > -1)
{
if(window.myLogger.force === true)
{
window.myLogger.original.apply(this,arguments);
}
}else {
window.myLogger.original.apply(this,arguments);
}
},
forceLogging:function(force){
window.myLogger.force = force;
},
original:function(){
return window.myLogger.original;
},
init:function(){
window.myLogger.original = console.log;
console.log = window.myLogger.log;
}
}
window.myLogger = logger;
console.log("this should print like normal");
window.myLogger.init();
console.log("this should not print");
window.myLogger.forceLogging(true);
console.log("this should print now");
Related
As the test suite grows I need to be able to run something in BeforeSuite() which will connect to external suite and skip the suite if an external resource is unavailable.
Feature('External Server');
BeforeSuite((I) => {
// Check if server is available and skip all scenarios if it is not
});
Scenario('Login to the server', (I) => {
// Do not run this if the server is not available
})
I understand I could probably set a variable, but I think it would be nice if there was a way to tell the runner that a suite has been skipped.
The goal is to have a suite marked as skipped in the output eg:
Registration --
✓ Registration - pre-checks in 4479ms
✓ Registration - email validation in 15070ms
✓ Registration - password validation in 8194ms
External Server -- [SKIPPED]
- Login to the server [SKIPPED]
maybe prepend x before every scenario in your feature? example xScenario. I don't think codecept supports something similar to only for features. it currently works with scenarios only as far as I know.
you can use
Scenario.skip
in your step definition to skip a scenario.
Note: if any steps have been executed before skipping then it will still show it in the report
https://codecept.io/basics/#todo-test
My answer is compiled from a number of comments on the CodeceptJS github and stackoverflow. However, I can't recall the exact links or comments which helped me derive this solution, it's been at least a year, maybe two, since I started and have slowly modified this.
Edit: Found the github thread - https://github.com/codeceptjs/CodeceptJS/issues/661
Edit2: I wrote a post about "selective execution" (which avoids tagging unwanted tests with skip status) https://github.com/codeceptjs/CodeceptJS/issues/3544
I'll add a snippet at the bottom.
I'm on CodeceptJS 3.3.6
Define a hook file (eg: skip.js) and link it to your codeceptjs.conf.js file.
exports.config = {
...
plugins: {
skipHook: {
require: "../path/to/skip.js",
enabled: true,
}
}
...
}
The basic code in skip.js is
module.exports = function () {
event.dispatcher.on(event.test.before, function (test) {
const skipThisTest = decideSkip(test.tags);
if (skipThisTest) {
test.run = function skip() {
this.skip();
};
return;
}
});
};
I've defined a decision function decideSkip like so:
function decideSkip(testTags) {
if (!Array.isArray(testTags)) {
output.log(`Tags not an array, don't skip.`);
return false;
}
if (testTags.includes("#skip")) {
output.log(`Tags contain [#skip], should skip.`);
return true;
}
if (
process.env.APP_ENVIRONMENT !== "development" &&
testTags.includes("#stageSkip")
) {
output.log(`Tags contain [#stageSkip], should skip on staging.`);
return true;
}
}
(Mine is a bit more complicated, including evaluating whether a series of test case ids are in a provided list but this shows the essence. Obviously feel free to tweak as desired, the point is a boolean value returned to the defined event listener for event.test.before.)
Then, using BDD:
#skip #otherTags
Scenario: Some scenario
Given I do something first
When I do another thing
Then I see a result
Or standard test code:
const { I } = inject();
Feature("Some Feature");
Scenario("A scenario description #tag1 #skip #tag2", async () => {
console.log("Execute some code here");
});
I don't know if that will necessarily give you the exact terminal output you want External Server -- [SKIPPED]; however, it does notate the test as skipped in the terminal and report it accordingly in allure or xunit results; at least insofar as CodeceptJS skip() reports it.
For "selective execution" (which is related but not the same as "skip"), I've implemented a custom mocha.grep() utilization in my bootstrap. A key snippet is as follows. To be added either to a bootstrap anonymous function on codecept.conf.js or some similar related location.
const selective = ["tag1", "tag2"];
const re = selective.join("|");
const regex = new RegExp(re);
mocha.grep(regex);
I have another question (last question). At the moment i am working on a Node.js project and in this I have many console.log() functions. This has worked okay so far but I also want everything that's written to the console to also be written in a log-file. Can someone please help me?
For example:
Console.log('The value of array position [5] is '+ array[5]);
In my real code its a bit more but this should give you an idea.
Thank you hopefully.
Just run the script in your terminal like this...
node script-file.js > log-file.txt
This tells the shell to write the standard output of the command node script-file.js to your log file instead of the default, which is printing it to the console.
This is called redirection and its very powerful. Say you wanted to write all errors to a separate file...
node script-file.js >log-file.txt 2>error-file.txt
Now all console.log are written to log-file.txt and all console.error are written to error-file.txt
I would use a library instead of re-inventing the wheel. I looked for a log4j-type library on npm, and it came up with https://github.com/nomiddlename/log4js-node
if you want to log to the console and to a file:
var log4js = require('log4js');
log4js.configure({
appenders: [
{ type: 'console' },
{ type: 'file', filename: 'logs/cheese.log', category: 'cheese' }
]
});
now your code can create a new logger with
var logger = log4js.getLogger('cheese');
and use the logger in your code
logger.warn('Cheese is quite smelly.');
logger.info('Cheese is Gouda.');
logger.debug('Cheese is not a food.');
const fs = require('fs');
const myConsole = new console.Console(fs.createWriteStream('./output.txt'));
myConsole.log('hello world');
This will create an output file with all the output which can been triggered through console.log('hello world') inside the console.
This is the easiest way to convert the console.log() output into a text file.`
You could try overriding the built in console.log to do something different.
var originalLog = console.log;
console.log = function(str){
originalLog(str);
// Your extra code
}
However, this places the originalLog into the main scope, so you should try wrapping it in a function. This is called a closure, and you can read more about them here.
(function(){
var originalLog = console.log;
console.log = function(str){
originalLog(str);
// Your extra code
})();
To write files, see this stackoverflow question, and to override console.log even better than the way I showed, see this. Combining these two answers will get you the best possible solution.
Just write your own log function:
function log(message) {
console.log(message);
fs.writeFileSync(...);
}
Then replace all your existing calls to console.log() with log().
#activedecay's answer seems the way to go. However, as of april 30th 2018, I have had trouble with that specific model (node crashed due to the structure of the object passed on to .configure, which seems not to work in the latest version). In spite of that, I've managed to work around an updated solution thanks to nodejs debugging messages...
const myLoggers = require('log4js');
myLoggers.configure({
appenders: { mylogger: { type:"file", filename: "path_to_file/filename" } },
categories: { default: { appenders:["mylogger"], level:"ALL" } }
});
const logger = myLoggers.getLogger("default");
Now if you want to log to said file, you can do it just like activedecay showed you:
logger.warn('Cheese is quite smelly.');
logger.info('Cheese is Gouda.');
logger.debug('Cheese is not a food.');
This however, will not log anything to the console, and since I haven't figured out how to implement multiple appenders in one logger, you can still implement the good old console.log();
PD: I know that this is a somewhat old thread, and that OP's particular problem was already solved, but since I came here for the same purpose, I may as well leave my experience so as to help anyone visiting this thread in the future
Here is simple solution for file logging
#grdon/logger
const logger = require('#grdon/logger')({
defaultLogDirectory : __dirname + "/logs",
})
// ...
logger(someParams, 'logfile.txt')
logger(anotherParams, 'anotherLogFile.log')
Assume I run my Javascript project in a browser and I'm inside a specific module, can I check whether is already message printed to the console ? i.e. read message from the console...
For example I'm inside my js.file inside function want to check if already printed hello world in the console.
jthanto's answer gave me an idea. I don't think it's good practice, but if you must, you can define your own console class:
var MyConsole = function(oldConsole) {
// store all messages ever logged
this.log = [];
// keep a pointer to oldConsole
this.oldConsole = oldConsole;
}
MyConsole.prototype.log = function(args) {
// push the message into log
this.log.push(Array.prototype.join.call(args));
// call oldConsole.log to actually display the message on the console
if (this.oldConsole)
this.oldConsole.log.apply(this.oldConsole, args);
}
// TODO: implement all other console methods in this fashion (apply for all console API methods)
MyConsole.prototype.<method> = function(args) {
if (this.oldConsole)
this.oldConsole.<method>.apply(this.oldConsole, args);
}
// method to check if something was printed
MyConsole.prototype.wasLogged(message) {
return this.log.indexOf(message)!==-1;
}
// replace console with an instance of MyConsole, pointing to the old console
console = new MyConsole(console);
Save it in a file and load it first (right at the top of your tags)
Use it like:
if (console.wasLogged("Hello World"))
doStuffz();
Hope it helps. Mind it's not tested, but should give you some pointers :)
You could always define your own function for "console.logging" one or more messages (if this is what you are doing), and have a boolean in this function to handle this sort of thing.
I would bet it's not "best practice", but it would solve your problem in some degree.
var messageSent = false;
var myConsoleLog = function($strMessage){
if (!messageSent) {
console.log($strMessage);
messageSent = true;
} else {
// Do whatever you feel like
}
};
Of course if you need to check for more cases you will need to alter the function to actually keep track of more messages. :)
Normally it can't be done. Look at Chrome console's API:
https://developer.chrome.com/devtools/docs/console-api
But this experimental Chrome feature can solve your problem: https://developer.chrome.com/extensions/experimental_devtools_console
Unfortunately it looks like other browsers doesn't have tools like this.
I currently have this JS statement everywhere in my code:
window.console && console.log("Foo");
I am wondering if this is costly at all, or has any negative side-effects in production.
Am I free to leave client-side logging in, or should it go?
EDIT: In the end, I suppose the best argument I (and anyone else?) can come up with is that there is a possibly non-negligible amount of extra data transferred between the server and the client by leaving logging messages left in. If production code is to be fully optimized, logging will have to be removed to reduce the size of javascript being sent to the client.
Another way of dealing with this is to 'stub' out the console object when it isn't defined so no errors are thrown in contexts that do not have the console i.e.
if (!window.console) {
var noOp = function(){}; // no-op function
console = {
log: noOp,
warn: noOp,
error: noOp
}
}
you get the idea... there are a lot of functions defined on the various implementations of the console, so you could stub them all or just the ones you use (e.g. if you only ever use console.log and never used console.profile, console.time etc...)
This for me is a better alternative in development than adding conditionals in front of every call, or not using them.
see also: Is it a bad idea to leave "console.log()" calls in your producton JavaScript code?
You should not add development tools to a production page.
To answer the other question: The code cannot have a negative side-effect:
window.console will evaluate to false if console is not defined
console.log("Foo") will print the message to the console when it's defined (provided that the page does not overwrite console.log by a non-function).
UglifyJS2
If you are using this minifier, you can set drop_console option:
Pass true to discard calls to console.* functions
So I would suggest to leave console.log calls as they are for a most trickiest part of the codebase.
If minification is part of your build process, you may use it to strip out debug code, as explained here with Google closure compiler: Exclude debug JavaScript code during minification
if (DEBUG) {
console.log("Won't be logged if compiled with --define='DEBUG=false'")
}
If you compile with advanced optimizations, this code will even be identified as dead and removed entirely
Yes. console.log will throw an exception in browsers that don't have support for it (console object will not be found).
Generally yes, its not a great idea to expose log messages in your production code.
Ideally, you should remove such log messages with a build script before deployment; but many (most) people do not use a build process (including me).
Here's a short snippet of some code I've been using lately to solve this dilemma. It fixes errors caused by an undefined console in old IE, as well as disabling logging if in "development_mode".
// fn to add blank (noOp) function for all console methods
var addConsoleNoOp = function (window) {
var names = ["log", "debug", "info", "warn", "error",
"assert", "dir", "dirxml", "group", "groupEnd", "time",
"timeEnd", "count", "trace", "profile", "profileEnd"],
i, l = names.length,
noOp = function () {};
window.console = {};
for (i = 0; i < l; i = i + 1) {
window.console[names[i]] = noOp;
}
};
// call addConsoleNoOp() if console is undefined or if in production
if (!window.console || !window.development_mode) {
this.addConsoleNoOp(window);
}
I'm pretty sure I took much of the above addConsoleNoOp f'n from another answer on SO, but cannot find right now. I'll add a reference later if I find it.
edit: Not the post I was thinking of, but here's a similar approach: https://github.com/paulmillr/console-polyfill/blob/master/index.js
var AppLogger = (function () {
var debug = false;
var AppLogger = function (isDebug) {
debug = isDebug;
}
AppLogger.conlog = function (data) {
if (window.console && debug) {
console.log(data);
}
}
AppLogger.prototype = {
conlog: function (data) {
if (window.console && debug) {
console.log(data);
}
}
};
return AppLogger;
})();
Usage:
var debugMode=true;
var appLogger = new AppLogger(debugMode);
appLogger.conlog('test');
Don't overcomplicate things! I personally use console.log all the time during development, it's just such a timesaver. For production i just add a single line of code (in the "production profile" in my case) that disable all logs:
window.console.log = () => {};
done ;)
This monkey patches window.console and replace the log function with an empty function, disabling the output.
This is good enough for me in most cases. If you want to go "all the way" and remove console.logs from your code to decrease bundle size, you have to change the way your js is bundled (e.g. drop console.logs with minifier or something)
Also I think you CAN actually make a strong point for leaving them in - even in production. It doesn't change anything for a normal user but can really speed up understanding weird "exotic-browser" problems. It's not like it's backend-logs that may contain critical information. It's all on the frontend anyway, not showing a log message because you are scared to reveal something a user shouldn't know really is only "security by obscurity" and should make you think why this information is even available on the frontend in the first place. Just my opinion.
Yes, its good practice to use console.log for javascript debugging purpose, but it needs to be removed from the production server or if needed can be added on production server with some key points to be taken into consideration:
**var isDebugEnabled="Get boolean value from Configuration file to check whether debug is enabled or not".**
if (window.console && isDebugEnabled) {
console.log("Debug Message");
}
Above code block has to be used everywhere for logging in order to first verify whether the console is supported for the current browser and whether debug is enabled or not.
isDebugEnabled has to be set as true or false based on our
environment.
TL;DR
Idea: Logging objects precludes them from being Garbage Collected.
Details
If you pass objects to console.log then these objects are accessible by reference from console of DevTools. You may check it by logging object, mutating it and finding that old messages reflect later changes of the object.
If logs are too long old messages do get deleted in Chrome.
If logs are short then old messages are not removed, if these messages reference objects then these objects are not Garbage Collected.
It's just an idea: I checked points 1 and 2 but not 3.
Solution
If you want to keep logs for sake of client-side troubleshooting or other needs then:
['log', 'warn', 'error'].forEach( (meth) => {
const _meth = window.console[meth].bind(console);
window.console[meth] = function(...args) { _meth(...args.map((arg) => '' + arg)) }
});
If the workflow is done using the right tools such as parcel/webpack then it's no longer a headache, because with the production build console.log is being dropped. Even few years earlier with Gulp/Grunt it could've been automated as well.
Many of the modern frameworks such as Angular, React, Svelte, Vue.js come with that setup out-of-the-box. Basically, you don't have to do anything, as long as you deploy the correct build, i.e. production one, not development which will still have console.log.
I basically overwrite the console.log function with the one what has knowledge of where the code is being run. Thus i can keep using console.log as I do always. It automatically knows that I am in dev/qa mode or in production. There is also a way to force it.
Here is a working fiddle.
http://jsfiddle.net/bsurela/Zneek/
Here is the snippet as stack overflow is intimated by people posting jsfiddle
log:function(obj)
{
if(window.location.hostname === domainName)
{
if(window.myLogger.force === true)
{
window.myLogger.original.apply(this,arguments);
}
}else {
window.myLogger.original.apply(this,arguments);
}
},
I know this is quite an old question and hasn't had much activity in a while. I just wanted to add my solution that I came up with which seems to work quite well for me.
/**
* Logger For Console Logging
*/
Global.loggingEnabled = true;
Global.logMode = 'all';
Global.log = (mode, string) => {
if(Global.loggingEnabled){
switch(mode){
case 'debug':
if(Global.logMode == 'debug' || Global.logMode == 'all'){
console.log('Debug: '+JSON.stringify(string));
}
break;
case 'error':
if(Global.logMode == 'error' || Global.logMode == 'all'){
console.log('Error: '+JSON.stringify(string));
}
break;
case 'info':
if(Global.logMode == 'info' || Global.logMode == 'all'){
console.log('Info: '+JSON.stringify(string));
}
break;
}
}
}
Then I typically create a function in my scripts like this or you could make it available in a global script:
Something.fail = (message_string, data, error_type, function_name, line_number) => {
try{
if(error_type == undefined){
error_type = 'error';
}
Global.showErrorMessage(message_string, true);
Global.spinner(100, false);
Global.log(error_type, function_name);
Global.log(error_type, 'Line: '+line_number);
Global.log(error_type, 'Error: '+data);
}catch(error){
if(is_global){
Global.spinner(100, false);
Global.log('error', 'Error: '+error);
Global.log('error', 'Undefined Error...');
}else{
console.log('Error:'+error);
console.log('Global Not Loaded!');
}
}
}
And then I just use that instead of console.log like this:
try{
// To Do Somehting
Something.fail('Debug Something', data, 'debug', 'myFunc()', new Error().lineNumber);
}catch(error){
Something.fail('Something Failed', error, 'error', 'myFunc()', new Error().lineNumber);
}
This question already has answers here:
How to quickly and conveniently disable all console.log statements in my code?
(38 answers)
Closed 2 years ago.
I have many console.log (or any other console calls) in my code and I would like to use them only
when my app is in some kind of "debug mode".
I can't seem to use some kind of logger function and internally use console.log because then I wouldn't know what line fired it. Maybe only with a try/catch, but my logs are very general and I don't want try/catch in my code.
What would you recommend?
I would probably abuse the short-circuiting nature of JavaScript's logical AND operator and replace instances of:
console.log("Foo.");
With:
DEBUG && console.log("Foo.");
Assuming DEBUG is a global variable that evaluates to true if debugging is enabled.
This strategy avoids neutering console.log(), so you can still call it in release mode if you really have to (e.g. to trace an issue that doesn't occur in debug mode).
Just replace the console.log with an empty function for production.
if (!DEBUG_MODE_ON) {
console = console || {};
console.log = function(){};
}
Clobbering global functions is generally a bad idea.
Instead, you could replace all instances of console.log in your code with LOG, and at the beginning of your code:
var LOG = debug ? console.log.bind(console) : function () {};
This will still show correct line numbers and also preserve the expected console.log function for third party stuff if needed.
Since 2014, I simply use GULP (and recommend everyone to, it's an amazing tool), and I have a package installed which is called stripDebug which does that for you.
(I also use uglify and closureCompiler in production)
Update (June 20, 2019)
There's a Babel Macro that automatically removes all console statements:
https://www.npmjs.com/package/dev-console.macro
One more way to disable console.log in production and keep it in development.
// overriding console.log in production
if(window.location.host.indexOf('localhost:9000') < 0) {
console.log = function(){};
}
You can change your development settings like localhost and port.
This Tiny wrapper override will wrap the original console.log method with a function that has a check inside it, which you can control from the outside, deepening if you want to see console logs and not.
I chose window.allowConsole just as an example flag but in real-life use it would probably be something else. depending on your framework.
(function(cl){
console.log = function(){
if( window.allowConsole )
cl(...arguments);
}
})(console.log)
Usage:
// in development (allow logging)
window.allowConsole = true;
console.log(1,[1,2,3],{a:1});
// in production (disallow logging)
window.allowConsole = false;
console.log(1,[1,2,3],{a:1});
This override should be implement as "high" as possible in the code hierarchy so it would "catch" all logs before then happen. This could be expanded to all the other console methods such as warn, time, dir and so on.
Simple.
Add a little bash script that finds all references to console.log and deletes them.
Make sure that this batch script runs as part of your deployment to production.
Don't shim out console.log as an empty function, that's a waste of computation and space.
This code works for me:
if(console=='undefined' || !console || console==null) {
var console = {
log : function (string) {
// nothing to do here!!
}
}
}
The newest versions of chrome show which line of code in which file fired console.log. If you are looking for a log management system, you can try out logeek it allows you to control which groups of logs you want to see.
// In Development:
var debugMode = true
// In Prod:
var debugMode = false
// This function logs console messages when debugMode is true .
function debugLog(logMessage) {
if (debugMode) {
console.log(logMessage);
}
}
// Use the function instead of console.log
debugLog("This is a debug message");
console can out put not just log but errors warnings etc.
Here is a function to override all console outputs
(function () {
var method;
var noop = function noop() { };
var methods = [
'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error',
'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log',
'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd',
'timeStamp', 'trace', 'warn'
];
var length = methods.length;
var console = (window.console = window.console || {});
while (length--) {
method = methods[length];
console[method] = noop;
}
}());
Refer to detailed post here
https://stapp.space/disable-javascript-console-on-production/