3

It's considered a good practice to use mdt to enable/disable system.debug info in Apex, meaning: using SOQL to checks the flag at the beginning of each execution. if it's true, then system.debug is written into the debug log.

I wonder if the same is recommended for LWC development to show console.log in the browser console? If so, does it run too many times of SOQL (even though against mdt is not counted for limits)?

Or maybe there are better ways?

3

System.debug and console.log statements should generally not be in production-released code. They are meant to aid in debugging before the code gets to a production environment. In compiled languages, there's usually a compiler flag for debug/production modes, and in production compilation, all debug statements are removed. This is an ancient practice that allowed developers to see how their code behaves, yet remove the bloat and CPU time sinks for their customers.

In the case of Apex, conditional debug statements can harm code coverage and/or test/deployment times, can leak sensitive information, and are generally CPU time sinks for the millions of transactions that will follow where no debug logs are generated. Even worse, as a CMDT, someone could accidentally package it in an "on" state and slow down the entire system for everyone, with literally no benefit.

In fact, I've proposed a code review rule with basically every team I've worked on that System.debug automatically fails the review. I even very nearly made a precommit rule forbidding the use of logging. It is both a CPU time sink and a potential security risk if not used correctly, so the safer alternative is to outright ban the use of debug statements.

Similarly, be wary of the use of console.log statements. While the user can inspect the memory state at any time, literally handing the customer potential "secrets" on a silver platter is generally not ideal. In addition, console.log statements take up both CPU time and memory. Excessive logging can harm browser performance, just as it can on other types of platforms.

Since there are better ways of debugging, such as literally using the debugging tool built in to the browser, there is no reason to log copious amounts of data to the console. You can use breakpoints, watchpoints, and other tools to efficiently examine what is happening in your code without any logging whatsoever. As far as client-side logging, it's not like there are actual "governor limits," but be aware that excessive logging can slow down a browser significantly.

So, summarized, it should be said that debug statements are for debugging code, not production code, and therefore you should never have any type of logging in your production code. If you need to debug a specific problem in production, you should add in the appropriate logging temporarily, install an upgrade package, and then revert the logging out when you're done. Alternatively, try to avoid debugging in production entirely. Create a Sandbox, add all manner of debugging in a Beta package, fully test it, then revert all of the debug logging when you make a Release package.

For First-Generation Managed Packages, this can be done by creating a Beta version with debugging code where you need it, which is then installed in to a Sandbox or Scratch Org for testing and replication. In Second-Generation Packaging, you can create an alternative "branch" by setting the appropriate ancestor, do whatever testing you need, then roll any fixes back in to the main branch. Afterwards, you can delete the side branch as it is no longer necessary.

4
  • The idea is indeed only to show debug info in prod temporarily by enabling the mdt flag. When it's disabled, all this debug info is gone. I also understand that using any debug info in the prod environment is bad. But in certain circumstances, it speeds up the troubleshooting time especially when the error can't be reproduced in test environment.
    – Xi Xiao
    Jan 11 at 7:58
  • I'm catching up on LWC's latest update. I have an old perception that the browser JS console debugger doesn't work well enough on LWC code due to its wrapping/security/locker thing?
    – Xi Xiao
    Jan 11 at 8:05
  • @XiXiao (a) It's still more likely that someone will cripple production than it will help fix a problem that can't be resolved any other way. A few debug statements are generally not fatal, but if your code is more debug statement than business logic, there's a significant risk of causing problems. (b) I debug LWCs all the time without the use of console.log. Again, definitely use debug statements during development, but you shouldn't need them in production.
    – sfdcfox
    Jan 11 at 14:03
  • got it and appreciate your help as always! @sfdcfox
    – Xi Xiao
    Jan 12 at 8:41
2

It is a good practice avoiding to flood the browser console with tons of console.log in a production environment and you won't get a too many SOQL in such case. Moreover you don't need a SOQL to retrieve a Custom Metadata, you can call getInstance().

Anyway there could be some cases in which you would like to enable/disable the console.log just for one (or few) LWC.
In order to do so, in the JS controller you could expose a public property to set the minimum logging level you want to allow, so you can easily set it via Lightning/Community/Flow builder.
Then you should enclose the console.log (or error, warn, etc...) in an if to check whether the level is allowed.

JS:

const LEVEL_NONE = 0;
const LEVEL_ERROR = 1;
const LEVEL_WARN = 2;
const LEVEL_INFO = 3;
const LOGGING_LEVELS_MAP = {
    'None': LEVEL_NONE,
    'Error': LEVEL_ERROR,
    'Warn': LEVEL_WARN,
    'Info': LEVEL_INFO,
};


_loggingLevel = LEVEL_NONE;
@api
get loggingLevel() {
    return this._loggingLevel;
}
set loggingLevel(value) {
    this._loggingLevel = LOGGING_LEVELS_MAP[value] ?? LEVEL_NONE;
}

testLoggingLevel() {
    if (this._loggingLevel <= LEVEL_INFO) {
        console.log('info log');
    }
    if (this._loggingLevel <= LEVEL_WARN) {
        console.warn('this is a warning');
    }
    if (this._loggingLevel <= LEVEL_ERROR) {
        console.error('Oh no!');
    }
}

Of course in the xml you must have an appropriate property:

<property label="Logging Level" name="loggingLevel" type="String" datasource="None,Error,Warn,Info" default="None" />

Starting from that, you can write an utility component to manage logs all over your application.

By the way, there are two cases in which SOQL for custom metadata count toward Apex governor limits:

  • SOQL queries in flows
  • SOQL queries containing long text area fields
1
  • Thanks for LEVELS_MAP idea combined with property, as well as the SOQL mdt explanation. I didn't aim to have a trigger on every single LWC, but maybe it is good for flexibility.
    – Xi Xiao
    Jan 11 at 7:56
1

As sfdcfox mentions, I'd also argue console.log and System.debug should be avoided if this is for production debugging. Other than using the debugging tools built into the browser, you can also consider building out a framework to handle logging in your org across a transaction depending on the information you're looking to monitor.

This typically involves having a custom object called Log that stores that information and can only be exposed to those who need it, typically the developers/admins.

There's a couple examples of logging approaches that you can leverage, as is, or dig into to see how they handle it. The first one, in particular, handles logging across LWC/Aura and Apex (as well as Flow/Process Builder).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.