Czy powinienem usunąć console.log z kodu produkcyjnego?

86

Obecnie mam to oświadczenie JS wszędzie w moim kodzie:

window.console && console.log("Foo");

Zastanawiam się, czy jest to w ogóle kosztowne, czy ma jakieś negatywne skutki uboczne w produkcji.

Czy mogę zostawić logowanie po stronie klienta, czy powinno to odejść?

EDYCJA: Ostatecznie wydaje mi się, że najlepszym argumentem, jaki mogę wymyślić (i kogokolwiek innego?), Jest to, że istnieje prawdopodobnie nie do pominięcia ilość dodatkowych danych przesyłanych między serwerem a klientem, pozostawiając wiadomości logowania. Jeśli kod produkcyjny ma być w pełni zoptymalizowany, logowanie będzie musiało zostać usunięte, aby zmniejszyć rozmiar kodu JavaScript wysyłanego do klienta.

Sean Anderson
źródło

Odpowiedzi:

41

Należy nie dodać narzędzi programistycznych do strony produkcyjnej.

Aby odpowiedzieć na inne pytanie: Kod nie może mieć negatywnego skutku ubocznego:

  • window.consolejeśli consolenie zostanie zdefiniowana, zostanie oceniona na false
  • console.log("Foo")wydrukuje wiadomość na konsoli, gdy jest zdefiniowana (pod warunkiem, że strona nie zostanie zastąpiona console.logprzez niefunkcję).
Rob W
źródło
43
W zasadzie zgadzam się z tobą. Ale myślę, że wszyscy zgodzilibyśmy się, że wdrożenie rejestrowania, które nie uruchamia się z wyjątkiem trybu debugowania, jest konieczne dla wysokiej jakości kodu po stronie serwera. Nikt nie przechodzi i nie usuwa ich logowania do wydania produkcyjnego - program określa, jaki poziom logowania jest niezbędny i odpowiednio reaguje. Mam nadzieję, że jest coś podobnego do programowania po stronie klienta ... nawet ustawienie zmiennej "isDebug", jeśli zajdzie taka potrzeba. Dlaczego miałbym chcieć obciążać następnego dewelopera koniecznością cofania się i ponownego dodawania logowania dla problematycznych obszarów w przyszłości?
Sean Anderson
11
Shabby jak? Twierdziłbym, że stwierdzenie, że konsola programisty jest częścią witryny produkcyjnej, jest jak powiedzenie, że pliki dziennika są częścią aplikacji. Tak, oba są generowane przez kod, ale należy w pewnym stopniu zrozumieć, że dzienniki należy gdzieś zostawić. Jednak to, czy oświadczenia w dziennikach są przyjazne dla użytkownika, czy nie, to inna sprawa.
Sean Anderson
4
Jak można automatycznie usunąć kod debugowania przed zminimalizowaniem? Komunikat dziennika po stronie klienta może przybierać wiele form.
Sean Anderson
6
Możesz oznaczyć każdy fragment kodu debugowania, na przykład poprzedzając / dodając wiersz kodu debugującego komentarzem. Przykład: /*DEBUG:start*/console.log("Foo");/*DEBUG:end*/. Następnie użyj RegExp, aby usunąć wszystkie wystąpienia /*DENUG-start*/[\S\s]*?/*DEBUG-end*/. Pozostałe znaki spacji zostaną usunięte przez minimizer.
Rob W
3
O ile ta odpowiedź nie mówi DLACZEGO nie powinieneś tego robić, to naprawdę nie jest przydatne. Mamy po prostu ślepo zaakceptować, że to jest złe, bez dowodów i powodów?
ESR
48

Innym sposobem radzenia sobie z tym problemem jest „odgięcie” obiektu konsoli, gdy nie jest on zdefiniowany, aby w kontekstach, które nie mają konsoli, nie są wyrzucane żadne błędy, tj.

if (!window.console) {
  var noOp = function(){}; // no-op function
  console = {
    log: noOp,
    warn: noOp,
    error: noOp
  }
}

masz pomysł ... istnieje wiele funkcji zdefiniowanych w różnych implementacjach konsoli, więc można je wszystkie, czy tylko te, które używają skrótową (np jeśli tylko kiedykolwiek używać console.logi nigdy nie używane console.profile, console.timeetc ...)

Jest to dla mnie lepsza alternatywa w rozwoju niż dodawanie warunkowych przed każdym połączeniem lub ich niestosowanie.

zobacz także: Czy pozostawienie wywołań „console.log ()” w swoim produkcie w kodzie JavaScript to zły pomysł?

Craigb
źródło
6
Dobry pomysł. Potrzebne tylko kilka poprawek. Debuger Visual Studio JS zgłasza pierwszy komunikat console.log = noOp (), ponieważ sam obiekt konsoli nie jest zdefiniowany. Zrobiłem to tak: console = {log: noOp, warn: noOp, error: noOp}. Zauważ również, że nie chcesz wstawiać () po noOp - chcesz przypisać samą funkcję, a nie jej wartość zwracaną. Testowane na debugerze Visual Studio JS i IE9 - teraz działa dobrze.
JustAMartin
3
FYI, jeśli jesteś już przy użyciu jQuery, zapewniają one funkcję noop: $.noop.
zmiażdżyć
28

UglifyJS2

Jeśli używasz tego minifier, możesz ustawić drop_consoleopcję :

Przekaż true, aby odrzucić wywołania do funkcji console. *

Dlatego sugerowałbym pozostawienie console.logpołączeń, ponieważ dotyczą one najtrudniejszej części kodu.

terales
źródło
3
Jeśli używasz chrząknięcia i uglify , ta sama opcja jest również dostępna (wydaje się, że uglify opiera się na UglifyJS2): github.com/gruntjs/ ...
Tilt
1
Pytanie brzmi „czy powinienem”, a nie „jak mam”.
ESR
Powinieneś zostawić console.errors w. Jeśli ktoś na produkcji ma problem, możesz go łatwo zdiagnozować. Nie zdejmuj konsoli. Błędów!
Oliver Watkins
Jeśli będzie potrzeba dla nich wtedy można po prostu ustawić drop_consolesię false, obserwować je i schować je ponownie.
terales
16

Jeśli minifikacja jest częścią procesu kompilacji, możesz jej użyć do usunięcia kodu debugowania, jak wyjaśniono tutaj w przypadku kompilatora zamknięcia Google: Wyklucz debugowany kod JavaScript podczas minifikacji

if (DEBUG) {
  console.log("Won't be logged if compiled with --define='DEBUG=false'")
}

Jeśli kompilujesz z zaawansowanymi optymalizacjami, ten kod zostanie nawet zidentyfikowany jako martwy i całkowicie usunięty

wutz
źródło
1
Dziękuję Ci! Szukałem tego. :)
Sean Anderson
5

Tak. console.log zgłosi wyjątek w przeglądarkach, które go nie obsługują (obiekt konsoli nie zostanie znaleziony).

MK_Dev
źródło
nie z jego oceną zwarcia, o ile okno jest zdefiniowane
Joe
1
Chociaż przegapiłem to w mojej początkowej odpowiedzi, sprawdź również console.log.
MK_Dev
Zwykle robię po prostu window.console, aby zapobiec kłopotom z IE. Jeszcze nie spotkałem się z sytuacją, w której dziennik został przypadkowo zastąpiony, ale jestem pewien, że może się to zdarzyć.
Sean Anderson
@MK_Dev Mianowicie, które przeglądarki?
goodpixels
Jest rok 2019. Wątpię, czy są jakieś przeglądarki, które nie obsługują konsoli.
Oliver Watkins
5

Generalnie tak, ujawnianie komunikatów dziennika w kodzie produkcyjnym nie jest dobrym pomysłem.

Najlepiej byłoby usunąć takie komunikaty dziennika za pomocą skryptu kompilacji przed wdrożeniem; ale wiele (większość) osób nie korzysta z procesu kompilacji (w tym ja).

Oto krótki fragment kodu, którego ostatnio używałem, aby rozwiązać ten dylemat. Naprawia błędy spowodowane przez niezdefiniowane consolew starym IE, a także wyłącza logowanie w "trybie deweloperskim".

// 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);
}

Jestem prawie pewien, że wziąłem wiele z powyższego addConsoleNoOpf'n z innej odpowiedzi na SO, ale nie mogę teraz znaleźć. Jeśli znajdę, dodam odniesienie później.

edytuj: Nie ten post, o którym myślałem, ale tutaj jest podobne podejście: https://github.com/paulmillr/console-polyfill/blob/master/index.js

Zach Lysobey
źródło
3
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;
})();

Stosowanie:

var debugMode=true;
var appLogger = new AppLogger(debugMode);
appLogger.conlog('test');
dynamiclynk
źródło
1

Tak, dobrą praktyką jest używanie go console.logdo celów debugowania javascript, ale należy go usunąć z serwera produkcyjnego lub w razie potrzeby dodać na serwerze produkcyjnym z kilkoma kluczowymi kwestiami, które należy wziąć pod uwagę:

**var isDebugEnabled="Get boolean value from Configuration file to check whether debug is enabled or not".**
if (window.console && isDebugEnabled) {
    console.log("Debug Message");
}

Powyższy blok kodu musi być używany wszędzie do logowania, aby najpierw sprawdzić, czy konsola jest obsługiwana przez bieżącą przeglądarkę i czy debugowanie jest włączone, czy nie.

isDebugEnabled musi być ustawiony jako prawda lub fałsz w zależności od naszego środowiska.

shanky
źródło
1

TL; DR

Pomysł: Rejestrowanie obiektów wyklucza ich zbieranie śmieci.

Detale

  1. Jeśli przekazujesz obiekty console.log te obiekty są dostępne przez odniesienie z konsoli DevTools. Możesz to sprawdzić, logując obiekt, mutując go i stwierdzając, że stare komunikaty odzwierciedlają późniejsze zmiany obiektu.
  2. Jeśli dzienniki są zbyt długie, stare wiadomości są usuwane w Chrome.
  3. Jeśli dzienniki są krótkie, stare komunikaty nie są usuwane, jeśli te komunikaty odwołują się do obiektów, wówczas te obiekty nie są usuwane bez pamięci.

To tylko pomysł: zaznaczyłem punkty 1 i 2, ale nie 3.

Rozwiązanie

Jeśli chcesz przechowywać dzienniki ze względu na rozwiązywanie problemów po stronie klienta lub w innych celach:

['log', 'warn', 'error'].forEach( (meth) => {
  const _meth = window.console[meth].bind(console);
  window.console[meth] = function(...args) { _meth(...args.map((arg) => '' + arg)) }
});
ilyaigpetrov
źródło
0

Zasadniczo nadpisuję funkcję console.log tą, która ma wiedzę o tym, gdzie kod jest uruchamiany. Dzięki temu mogę nadal korzystać z console.log, jak zawsze. Automatycznie wie, że jestem w trybie dev / qa lub w produkcji. Jest też sposób, aby to wymusić. Oto działające skrzypce. http://jsfiddle.net/bsurela/Zneek/

Oto fragment, ponieważ przepełnienie stosu jest zastraszane przez osoby wysyłające plik 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);
    }
},
Bhavin
źródło
0

Wiem, że to dość stare pytanie i od jakiegoś czasu nie było zbyt aktywne. Chciałem tylko dodać moje rozwiązanie, które wymyśliłem, a które wydaje mi się całkiem dobre.

    /**
     * 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;
            }
        }
    }

Następnie zazwyczaj tworzę funkcję w moich skryptach, takich jak ten lub możesz udostępnić ją w globalnym skrypcie:

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!');
        }           
    }   
}

A potem używam tego zamiast console.log w ten sposób:

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);
}
Kyle Coots
źródło
0

Jeśli przepływ pracy jest wykonywany przy użyciu odpowiednich narzędzi, takich jak parcel/, webpackto już nie jest ból głowy, ponieważ wraz z upuszczaniem productionkompilacji console.log. Jeszcze kilka lat wcześniej z Gulp/ Gruntto również mogło zostać zautomatyzowane.

Wiele współczesnych ram, takich jak Angular, React, Svelte, Vue.jspochodzą z tej instalacji out-of-the-box. Zasadniczo nie musisz nic robić, o ile wdrożysz poprawną kompilację, tj. productionTaką, developmentktórej nadal nie będziesz mieć console.log.

Daniel Danielecki
źródło