如何避免将调试代码放入生产环境?

29

这种情况发生在我们中的最佳人选身上。

alt text

特别是当处理没有内置调试功能(如断点和监视变量)的语言时,这些错误会困扰开发人员。调试代码、警报和 Response.Writes 会出现在生产代码中。

如何将 JavaScript、PHP 或 VBScript 中的调试问题与功能代码分离?如何确保这些调试更改永远不会进入生产环境?


19
使用最近的事件来引入问题,这是一个好方法,加1分 :) - Pekka
我还以为是因为我在搞浏览器的 cookie 设置,才看到了这个。 - FrustratedWithFormsDesigner
@Pekka:我正要发布完全相同的句子 ;) - jwueller
2
http://meta.stackexchange.com/questions/71780/lol-debugging-are-we-so-homepage-alerts-false - ajreal
17个回答

13
最简单的方法
define("DEBUG", true);


if (DEBUG) {
    echo "Debug Method";
}

对于 JavaScript 来说,情况类似。


3
+1 我喜欢这个答案。有一种论调认为,除了在生产环境中永远不运行之外,调试代码也不应该存在于生产代码中。 - Thomas Langston
这正是我们公司的做法。 - Stephen
@Pekka 这个例子是用PHP写的。Joel编辑的是Javascript。不知道JS是否知道define(),但至少它根本不是JS的意图。 - KingCrunch
2
这是一种不好的做法。请参考http://php.net/manual/en/language.constants.php#52008获取一个好的例子。 - vbence
@KingCrunch,这不是关于新功能的问题,而是关于如何以正确的方式实现它。 :) 对示例代码进行小修改即可解决。 - vbence
显示剩余2条评论


2

一种方法是使用环境变量。在您的服务器配置中,您可以设置一个环境变量来指示是否启用调试模式。生产服务器将配置为 false,而开发服务器则为 true。这样,您在代码中所做的就是检查环境变量:

在 PHP 中:

if (getenv('DEBUG_MODE')) {
    var_dump($foo);
}

这样一来,就不会忘记关闭它,因为它会自动关闭。但是如果你真的需要在生产环境中打开它,只需切换开关...


我的理解是,使用这种方法会为整个环境打开调试功能,而不是特定的组件。这个理解正确吗? - Thomas Langston
好的,这将会为整个服务器打开它。这是基于生产环境和开发环境分别运行在不同服务器上(还有预上线环境,因为通常不会在开发环境中关闭调试)。您可以始终设置一组按位设置的常量以启用不同的组件... - ircmaxell
您还可以根据IP/端口/DNS自动更改环境。 - JF Dion
我曾经看到过一些代码使用URL作为调试代码的关键,但我担心主机文件或其他机制被用来显示这些调试信息。 - Thomas Langston

2

有几种方法可以在生产环境中隐藏调试代码,但很少有方法可以删除它(当编译器无法自动删除它时)。

我通过以下方式隐藏调试代码:

  • 只在登录用户为开发人员或测试人员时显示它。
  • 在服务器端输出到日志/数据库。

我通过在部署前搜索特殊注释来删除它:

  • alert("false") //TODO:REMOVE DEBUG CODE

我的同事还建议:

  • 覆盖 alert 来检查调试变量。(可能会有副作用?)
  • 编写一个 alertDebug 方法来检查调试变量。(是否有人会记得它?)
  • 检查 firebug 是否正在运行

    if(window.console && window.console.firebug) { alert("you are using firebug"); }


2
虽然并不完美,但我在我的编辑器中设置了一个宏,可以添加调试内容并用适当的标记注释进行包装。我还编写了一个脚本,稍后会将这些内容删除。虽然最初有些犹豫,但随着时间的推移,我已经变得更加信任这个机制。
我的偏好是尽量避免检查调试代码。显然,像其他“规则”一样,也有例外情况,但因为以后很容易忽略,所以我不喜欢检查它。

+1 如果实际上删除了调试代码并自动化了该过程。 - Thomas Langston
我认为,如果你将源代码控制自动化以拒绝带有调试代码的提交,那么你可能会拥有比目前任何方案都更卓越的工作流程。 - Thomas Langston
你能提供一下用于剥离调试代码的代码吗?我很想看一个可行的例子。 - jveazey

1
作为最受欢迎的答案存在安全漏洞,让我包含一个更少风险的版本来自 php.net
define ('DEBUG', 1);

if (DEBUG == 1) {
   // echo some sensitive data.
}

基础知识相同,但如果未声明常量 DEBUG,则此代码不会执行调试代码。 if (DEBUG) 的问题在于,如果未定义该常量,则它将假定字符串“DEBUG”,这将被评估为 true。

1

如果您使用为调试目的指定的语言特性,则此类情况往往会发生得更少:

 assert( is_string($param1) );

不会影响生产代码。


1
如果只是"避免在生产环境中进行调试",那么可以使用内置的assert()函数。
这样可以完全避免处理调试信息,并防止其中可能存在的计算消耗内存或处理能力。
assert在生产环境中完全被忽略。
function debug(...$stuff){
    var_dump($stuff);
    return true; //always return true so assert will always pass it.
}
assert(debug("This code will not even be processed on production server. "));

这是最安全的方法,但不太灵活。

我经常使用的一种方法是检查主机名或客户端IP地址。

因此,我有一个检查主机名的函数,如下所示:

function onTestServer(){
    $SERVER_NAME = $_SERVER["SERVER_NAME"];

    if(substr($SERVER_NAME,-5)==="te.st") return true;//all *.te.st domains are test servers
    if (strpos($SERVER_NAME, ".localhost")!==false) return true; //all *.localhost domains are test servers
    return false;
}

然后我有自己的vardump、debug和die语句,类似于这样,在生产环境中不会执行:

function varDump($stuff){
    if (!onTestServer()) return;
    echo "<pre>";
    var_dump($stuff);
    echo "</pre>";
}

那么你只需要使用自定义的varDump()函数,这样只有你能看到它。

我的调试函数更加复杂,可以显示可展开的信息树等。但基本原则是相同的。如果在本地主机上,则执行vardumps等操作,否则不会显示任何内容。

当测试时总想看到额外的信息,但又不想在部署到服务器之前删除所有vardumps时,这个功能非常方便。

我还会检查客户端IP地址,并且如果客户端IP地址是我的话,在实际生产服务器上显示错误和信息。

function getIp()
{
    if (!empty($_SERVER['HTTP_CLIENT_IP']))   //check ip from share internet
    {
        $ip=$_SERVER['HTTP_CLIENT_IP'];
    }
    elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR']))   //to check ip is pass from proxy
    {
        $ip=$_SERVER['HTTP_X_FORWARDED_FOR'];
    }
    else
    {
        $ip=$_SERVER['REMOTE_ADDR'];
    }
    return $ip;
}

function onTestClient(){
    $office_ip = "xxxx.xxxx.xxxx.xxxx";
    $test_client_ips = array($office_ip,"any other ip you want");
    $client_ip = getIp();
    if (in_array($client_ip,$test_client_ips)) return true;
    return false;
}

如果您需要在没有本地测试环境的情况下从便携式计算机对现场站点进行快速更新的测试,那么这将非常方便。只需将当前IP添加到列表中,然后使用此类功能:

function die_dev($message){
    if (onTestServer() || onTestClient()) die($message);
}

甚至是:

if (onTestClient()){
    //show a completely different interface/webpage html js etc
} else {
    //show the original content that is currently live
}

0

我在调试代码时遵循三条规则

第一,让源代码看起来很糟糕,通过添加注释、缩进和空格来使其更易于阅读。

第二,使用打印语句输出变量的值,以便在运行时检查它们是否正确。

第三,使用调试器逐步执行代码,以便可以跟踪程序的执行过程并找到错误。

 not indenting it from the left margin

 egregiously violating the coding standard

 putting in extra whitespace above and below

设置一个全局调试开关,并

 have it alter an obvious output if it is ON, and

 make the debug code compilation depend on that switch being ON (i.e., so the code won't compile if the global switch is OFF)

破坏明显的输出,例如:

 delete something really important

 put up 99/99/99, for the date

 comment out the "File Load" function

 delaying the splash-screen

 etc.

这三条规则对我来说非常有效。


0

我所做的是用PHP编程。

define ("DEBUG", true);


function op (){
    if ( !DEBUG ) return true;

    $args = func_get_args();

    foreach ( $args as $var ){
        if ( is_object ( $var ) or is_array ( $var ) ){
            print "<br /><pre>";
            print_r ( $var );
            print "</pre>";

        }
        else{
            print "<br />" . $var;
        }
    }

        return true;
}

// On places to check 
op ($array, $var);

在 JavaScript 中,我也会做同样的事情

function calert(message){
    if (!debug) return;
    alert (message);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接