zoukankan      html  css  js  c++  java
  • 调试,测试与日志

     问题

    “程序的显示看起来有点问题,你能不能修改一下?”
    “没问题,改完我就提交给你。”
    “不会太久吧?”
    “5分钟就够了!”

    在软件开发过程中,这种场景屡见不鲜,但是,看起来很见的任务,其实往往不是那么简单。
    当修改了部分代码之后,程序不是像我们想象的那样工作,奇奇怪怪地问题开始出现,我们开始设置一个个的断点,一遍一遍地重复执行,眼睛紧紧盯着显示器上的监视窗口,时间在飞快地流逝,然而,我们的思路却渐渐变得模糊......有的时候,甚至没有监视到希望的步骤,不得不再一次重新开始。

    调试

    调试,又称 Debug,是开发工具赋予我们的一大利器,允许我们将程序的执行过程暂停在某一个点上,然后仔细观察当前程序的执行状态,以便于发现错误的蛛丝马迹。因此,成为程序员解决开发中问题的终极武器,甚至有的程序员在没有调试器的情况下,难以解决问题。

    但是,有的程序确实是难以调试的,例如,已经部署到客户环境中的程序,或者是 Windows 的服务程序,这个时候,我们是没有调试器可用的,那么,我们怎么办呢?

    于是,问题来了,我们为什么一定要调试呢?
    通过调试器,我们可以知道程序的运行状态。

    那么,我们为什么要知道程序的运行状态呢?
    因为程序太复杂了,我们不能一目了然地知道程序的运行状态。

    测试

    还有一种解决开发中问题的思路称为测试,又称为 Test,通过为程序编写一个个的测试用例,来保证程序在我们的掌控之中。由于从程序的第一步开始,我们就会通过测试来保证程序的正确,那么,在每一次的修改之后,我们就可以迅速地发现修改造成的影响。

    为了保证能够迅速写出测试,测试驱动的开发会强制你写出短小易懂、功能内聚、耦合松散的代码,把你从调试中解放出来。

    但是,对于复杂的操作,我们就不需要知道程序的状态了吗?完全通过测试就可以解决所有的问题吗?

    当然不是,不过,可以借助于日志来帮助我们记录程序的状态。而不再需要我们紧盯着监视窗口。

    日志

    日志,又称为 Log,是我们开发人员的又一利器,其实,不管是在调试还是测试的时候,日志都可以帮助我们解决问题,不过,很多的程序员迷恋于调试器,而忽视了日志。尤其是在测试驱动的开发中,日志更是我们的得力助手。
    所谓的日志,其实是一种记录机制,允许我们在程序代码中插入一些特殊的输出代码,将程序当前的运行状态随时输出,以便于在无人值守的情况下记录信息,在事后对程序的处理过程进行分析。

    最简单的日志就是直接通过 Console 来输出,或者使用 alert, 或者 MessageBox 来输出,没准你就使用过这些手法。这些方法会给程序带来副作用,在开发完成之后,往往需要你手工删除。不删除的话会造成程序的效率问题。要是又发现有新的问题存在呢?是不是又要再来一遍?这可是开发人员的噩梦呀!

    一个完善的日志系统绝不是简单地在控制台输出,它至少需要支持下面的几个特征:

    • 使用一种方式就支持输出到多个目的地,例如:控制台,文本文件,数据库,甚至电子邮件等等。
    • 允许控制输出的级别,过滤输出的内容,而不需要大幅度修改日志程序
    • 使用简单,可以使用简单的语法来记录日志

    目前,存在着多个成熟的日志系统供我们选择,在 .NET 开发平台上,主要有两个日志系统:.NET 平台直接支持的日志系统和开源的 Log4Net。

    今天,我们先看看 .NET 平台内置的日志系统。

    这里我们首先了解三个概念:

    • 日志器:用来发送日志,在开发中,主要是用日志器来输出日志信息。
    • 监听器:日志器用来输出日志信息,日志信息输出到哪里呢? 监听器用来完成实际的日志记录功能,在日志系统中,存在多种监听器,用来将日志信息记录到不同的目的地。
    • 日志控制开关:在软件生命周期的不同阶段,我们需要不同的日志信息,在开发阶段,可能需要比较详细的日志来检查错误,在运行阶段,大部分的问题已经被处理,我们可能仅仅需要记录一些关键信息,通过控制开关,可以在不需要修改代码的情况下,调整日志输出的内容。

    在 .NET 中,关于日志处理的相关类型,定义在命名空间 System.Diagnostics 中,有两个预定义的日志器类型,Debug 和 Trace。
    这两个日志记录器的工作机制是相同的,区别仅仅在于 Debug 仅仅在编译器定义了 DEBUG 常量的情况下工作,而 Trace 仅仅在定义了 TRACE 常量的情况下工作,默认情况下,当 我们使用 Debug 模式编译的时候,默认已经定义了这两个常量。所以,不管使用 Debug 还是 Trace 都可以输出日志信息。如果我们将程序编译为发布模式,那么,将仅仅定义 TRACE 常量,导致忽略 Debug 的存在,只记录 Trace 的日志信息。

    我们先看一看监听器,以便能够看到输出的日志信息。
    所有的监听器都要从 TraceListener  派生,这是定义在命名空间 System.Diagnostics 中的一个抽象基类。通常我们直接使用系统的一些派生类。

    System.Diagnostics.DefaultTraceListener
    System.Diagnostics.Eventing.EventProviderTraceListener
    System.Diagnostics.EventLogTraceListener
    System.Diagnostics.TextWriterTraceListener
    System.Web.WebPageTraceListener
    

    作为文本格式的日志, System.Diagnostics.TextWriterTraceListener 又有几个常用的派生类

    System.Diagnostics.ConsoleTraceListener
    System.Diagnostics.DelimitedListTraceListener
    System.Diagnostics.EventSchemaTraceListener
    System.Diagnostics.XmlWriterTraceListener
    


    Debug 和 Trace 使用相同的监听器,默认情况下,在它们的监听器集合属性 Listeners 中,已经添加了一个 System.Diagnostics.DefaultTraceListener 的实例,以便输出到 Visual Studio 的 Output 窗口中,所以,在使用了日志之后,我们可以打开 Output 窗口来看看实际的输出。如果我们希望能够在控制台窗口中看到输出,那么只需要增加一个 ConsoleTraceListener 就可以了。

    // 增加一个可以输出到控制台的 Listener
    System.Diagnostics.Trace.Listeners.Add(
        new System.Diagnostics.ConsoleTraceListener()
        );
    

    当然,在实际的开发中,我们可能需要的是一个文本文件,现在,你还需要提供一个文件名了。

    System.Diagnostics.Trace.Listeners.Add(
        new System.Diagnostics.TextWriterTraceListener("log.txt")
        );
    

    这些监听器也可以不在程序中固定声明,而是通过配置文件来更加方便地定义。这样的话,我们就可以动态地修改监听器,而不需要修改我们的代码了。
    在程序的配置文件中,配置节 system.diagnostics 用来定义日志的配置参数,其子元素 trace 定义日志的参数,trace 的子元素 listeners 定义日志的监听器。我们可以通过下面的配置参数来增加一个文件的监听器。其中的 initializeData 用来配置文件名。

    <add name="fileListener"
            type="System.Diagnostics.TextWriterTraceListener"
            initializeData="log.txt" />
    

    当监听器配置好之后,就可以使用日志器输出日志了。不管是 Debug 还是 Trace 都提供了多个方法来输出日志。
    最简单的方式就是使用 WriteLine 来输出日志,就跟使用 Console 一样。
    不过,对于日志来说,存在的一个问题就是,我们并不总想输出所有的日志,比如程序已经经过测试,我们可能并不需要大量的日志信息来干扰我们,怎么减少实际输出的日志呢?修改程序当然不是一个好主意,我们可以通过条件输出来限制输出的日志内容,仅仅在某种条件下,才输出日志,通过 WriteLineIf ,我们可以指定一个条件,仅仅当条件满足的时候,才会输出日志。

    条件仅仅是一个条件,什么样的条件都可以,只要你需要。

    为了方便使用,在 .NET 中又提供了一个日志的开关,来方便我们指定条件,所谓日志的开关其实就是一个从 0 到 4 的整数,通过一个枚举 TraceLevel 来方便使用这个整数

    • 0. 关闭,不希望输出日志
    • 1. 错误级别的日志
    • 2. 建议输出错误和警告级别的日志
    • 3. 一般信息的日志也输出
    • 4. 详细日志

    不过,实际上输出什么日志还是看你的日志输出语句,你在日志输出语句中可以通过这个开关来判断该不该输出。

    那么,这个开关从哪里取得呢?还是配置文件。在配置文件的 system.diagnostics 中,子元素 switches 用来配置一个日志级别,你需要为你的级别起一个名字,以便在程序中

    取得这个设置。

    <add name="traceSwitch" value="0"/>
    

    在程序中,你可以这样取得配置文件中日志的开关

    System.Diagnostics.TraceSwitch myTraceSwitch =
        new System.Diagnostics.TraceSwitch("traceSwitch", string.Empty);
    

    在程序中,你可以通过这个开关的设置来决定输出什么,配合开关的级别,在 Trace 中又提供了几个匹配的方法

    System.Diagnostics.Trace.TraceError("Error!!!");
    System.Diagnostics.Trace.TraceWarning("Warning!!!");
    

    当然,它们仅仅用来输出分类的日志,注意,判断是否输出是你的事情,所以,程序的代码往往如下:

    if( myTraceSwitch.TraceError)
        System.Diagnostics.Trace.TraceError("Error!!!");
    
    if( myTraceSwitch.TraceWarning)
        System.Diagnostics.Trace.TraceWarning("Warning!!!");
    

  • 相关阅读:
    循环神经网络(LSTM和GRU)(1)
    threading包的例子和queue包的例子
    xgboost调参
    理解 Python 中的 *args 和 **kwargs
    TFRecords文件的生成和读取(1)
    tensorflow函数介绍(4)
    python其他篇(1)
    python实现Restful服务(基于flask)(2)
    开源多线程性能测试工具-sysbench
    MySQL 8.0.0 版本发布,亮点都在这了!
  • 原文地址:https://www.cnblogs.com/haogj/p/2130186.html
Copyright © 2011-2022 走看看