相信你一定用日記寫過點滴心事,或是用空間、微信、微博刷著動態,記錄你每天的喜怒哀樂!在程序中也有一種類似的東西,記錄著他主人(應用程序)每天的行蹤,他叫日志(log)。日記——是人類生活的記事本,日志(log)——是程序運行狀況的記事本。
顧名思義,日志(log,後面均以log稱之)就是用來記錄程序每天的運行狀況的,比如程序出現異常的情況,或是某個關鍵點,功某個重要的數據或交易等。這裡的每天不是說每天一記,可以是伴隨著程序運行的始終,只要程序在運行著就一直在記錄,一般一天的日志記錄在同一個文件中,每天的日志以不同的文件名分開。
下面讓我們看看log在C++、Java、JavaScript中的記錄方式。
C++中有很多記錄log的庫,比較常用的有log4cpp(log4cxx)、Google Glog 。下面主要講一個log4cpp(log4cxx)的用法。
log4cxx是apache軟件基金會的一個開源庫,是由log4j移植過來的跨平台的日志處理跟蹤項目。從官網下載的log4cxx只有源碼,需要自己編譯。
1.下載apache-log4cxx-0.10.0.zip、apr-1.2.11-win32-src.zip、apr-util-1.2.10-win32-src.zip。
2.解壓apache-log4cxx-0.10.0.zip、apr-1.2.11-win32-src.zip、apr-util-1.2.10-win32-src.zip。
3.重命名apr-1.2.11為apr,重命名apr-util-1.2.10為apr-util;並將apr和apr-util拷貝apache-log4cxx-0.10.0根目錄下。
4.以管理員的身份運行cmd.exe,並定位到log4cxx的當前apache-log4cxx-0.10.0目錄下,執行以下命令:
configure
configure-aprutil
當執行configure-aprutil時,提示:“ 'sed' 不是內部或外部命令,也不是可運行的程序或批處理文件”。這是因為 configure-aprutil.bat 文件中使用了 Linux 下的 sed 命令,windows下找不到sed命令。解決的方法有以下幾種:1.下載一個sed for windows的工具;2.使用Cygwin(windows平台上運行的類UNIX模擬環境 ),再運行 configure-aprutil.bat;3.手動修改。
還是手動改來的方便,將.\apr-util\include\apu.hw下的#define APU_HAVE_APR_ICONV 1改為#define APU_HAVE_APR_ICONV 0 將.\apr-util\include\apr_ldap.hw下的#define APR_HAS_LDAP 1改為#define APR_HAS_LDAP 0。
5.用VC6或更高版本的Visual Studio工具打開 projects/log4cxx.dsw,在打開的時候會依次要求你選擇apr、aprutil、xml工程的工作目錄,在apache-log4cxx-0.10.0的子目錄中找到對應的apr.dsp、aprutil.dsp、xml.dsp文件打開即可。
6.選擇log4cxx為Active工程並編譯。
7.在編譯過程中可能報錯:無法打開包括文件:“apr.h”和“apu.h”,找到對應的apr.hw重命名為apr.h,apu.h重命名為apu.h即可。
<1>簡單樣例:
創建一個工程,設置log4cxx的頭文件路徑和lib庫的路徑,並加載log4cxx.lib文件。測試代碼如下,日志信息會在命令行中輸出。
#include "stdafx.h" #include "log4cxx/logger.h" #include "log4cxx/basicconfigurator.h" #include "log4cxx/helpers/exception.h" using namespace std; using namespace log4cxx; using namespace log4cxx::helpers; int main() { //@todo 重定向到文件 LoggerPtr logger(Logger::getLogger("LogTest")); //初始化配制 BasicConfigurator::configure(); //輸出DEBUG級別的日志 LOG4CXX_DEBUG(logger, "debug log"); //輸出TRACE級別的日志 LOG4CXX_TRACE(logger, "debug log"); //輸出INFO級別的日志 LOG4CXX_INFO(logger, "info log"); //輸出WARN級別的日志 LOG4CXX_WARN(logger, "debug log"); //輸出ERROR級別的日志 LOG4CXX_ERROR(logger, "debug log"); //輸出FATAL級別的日志 LOG4CXX_FATAL(logger, "debug log"); //ASSERT判斷條件是否正確, 條件為false時,輸出信息 LOG4CXX_ASSERT(logger, 1 == 2, "1 == 2"); return 0; }
注:我用VC6.0編譯log4cxx的源碼,然後在VS2010中使用log4cxx庫時,編譯會報錯:unresolved external symbol "__declspec(dllimport) public: void __thiscall log4cxx::Logger::forcedLog
這是因為不同版本的編譯器編譯的庫可能會有不同,要在VS2010上使用,需要在VS2010上重新編譯源碼。
<2>.設置配制文件:
如果要將日志信息輸出到文件,或同時輸出到命令行和文件,則要修改配制文件。
log4cxx.properties:
# 設置root logger為DEBUG級別,使用了ca和fa兩個Appender log4j.rootLogger=DEBUG, consoleAppender, fileAppender #對Appender fileAppender(輸出到文件)進行設置: # 這是一個文件類型的Appender, log4j.appender.fileAppender=org.apache.log4j.FileAppender # 將日志信息輸出到./log4cxxTest.log, log4j.appender.fileAppender.File=./log4cxxTest.log # 輸出方式為文件末尾追加 log4j.appender.fileAppender.Append=true # 設置輸出格式(layout)為PatternLayout log4j.appender.fileAppender.layout=org.apache.log4j.PatternLayout #log4j.appender.fileAppender.layout.ConversionPattern=%d [%t] %-5p %.16c - %m%n #對Appender consoleAppender(輸出到控制台)進行設置 log4j.appender.consoleAppender=org.apache.log4j.ConsoleAppender # 這是一個控制台類型的Appender log4j.appender.consoleAppender.layout=org.apache.log4j.PatternLayout # 輸出格式(layout)為PatternLayout log4j.appender.consoleAppender.layout.ConversionPattern=%d [%t] %-5p %.16c - %m%n
代碼:
#include "stdafx.h" #include "log4cxx/logger.h" #include "log4cxx/PropertyConfigurator.h" using namespace std; using namespace log4cxx; using namespace log4cxx::helpers; int main() { //用指定的文件加載配制 log4cxx::PropertyConfigurator::configure("E:/Test/log4cxx.properties"); //創建logger LoggerPtr logger = Logger::getLogger("test"); //輸出DEBUG級別的日志 LOG4CXX_DEBUG(logger, "debug log"); //輸出TRACE級別的日志 LOG4CXX_TRACE(logger, "debug log"); //輸出INFO級別的日志 LOG4CXX_INFO(logger, "info log"); //輸出WARN級別的日志 LOG4CXX_WARN(logger, "debug log"); //輸出ERROR級別的日志 LOG4CXX_ERROR(logger, "debug log"); //輸出FATAL級別的日志 LOG4CXX_FATAL(logger, "debug log"); //ASSERT判斷條件是否正確, 條件為false時,輸出信息 LOG4CXX_ASSERT(logger, 1 == 2, "1 == 2"); return 0; }
Java中給項目程序添加log主要有三種方式,一使用JDK中的java.util.logging包,一種是log4j,一種是commons-logging。其中log4j和commons-logging都是apache軟件基金會的開源項目。這三種方式的區別如下:
Java.util.logging,JDK標准庫中的類,是JDK 1.4 版本之後添加的日志記錄的功能包。
log4j,最強大的記錄日志的方式。可以通過配置 .properties 或是 .xml 的文件, 配置日志的目的地,格式等等。
commons-logging,最綜合和常見的日志記錄方式,是Java中的一個日志接口,一般會與log4j一起使用。自帶SimpleLog可用於日志記錄。
【例1.1】:日志的簡單使用
package lwf.log.test; import java.util.logging.Logger; public class LogTest { static String strClassName = LogTest.class.getName(); static Logger logger = Logger.getLogger(strClassName); public static double division(int value1, int value2) { double result = 0; try { result = value1 / value2; } catch(ArithmeticException e) { logger.warning("除數不能為0."); e.printStackTrace(); } return result; } public static void main(String[] args) { System.out.println(division(5, 0)); } }
從這個例子中你會看到控制台上輸出了日期時間,類名,方法名和“[warning]除數不能為0.”的信息。<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD48cD5Mb2dnZXLKx0phdmEgTG9nZ2luZyBBUEnW0LXE0ru49sDgo6xMb2dnZXIuZ2V0TG9nZ2Vyt723qLS0vajBy9K7uPZMb2dnZXLKtcD9oaPDv9K7uPZMb2dnZXLKtcD9tryx2NDr09C49sP7s8ajrM2os6O1xNf2t6jKx8q508PA4MP7s8a2qNLlTG9nZ2VyyrXA/aGjPC9wPjxwPmxvZ2dlci53YXJuaW5nt723qNPDwLTK5LP2yNXWvtDFz6KjrLP9wct3YXJuaW5ntKajrLu509BzZXZlcmWhomluZm+1yKGjztLDx7/J0tSw0aG+wP0xob/U2bjE0rvPwqOsyMPG5Mrks/a499bWyNXWvtDFz6KhozwvcD48cD4gPC9wPjxwPiA8L3A+PHA+ob7A/TEuMqG/o7rI1da+tcS8trHwPC9wPjxwPjwvcD48cHJlIGNsYXNzPQ=="brush:java;">public static double division(int value1, int value2) {
double result = 0;
try {
result = value1 / value2;
} catch(ArithmeticException e) {
logger.severe("[severe]除數不能為0.");
logger.warning("[warning]除數不能為0.");
logger.info("[info]除數不能為0.");
logger.config("[config]除數不能為0.");
logger.fine("[fine]除數不能為0.");
logger.finer("[finer]除數不能為0.");
logger.finest("[finest]除數不能為0.");
e.printStackTrace();
}
return result;
}
結果:
Java Logging API提供了七個日志級別用來控制輸出。這七個級別分別是:
級別
SEVERE
WARNING
INFO
CONFIG
FINE
FINER
FINEST
調用方法
severe()
warning()
info()
config()
fine()
finer()
finest()
含意
嚴重
警告
信息
配置
良好
較好
最好
但在上面的例子中我們可以看到只輸出了SEVERE、WARNING、INFO三個等級的日志,並沒有如我們相像中的好樣輸出各個級別的日志信息。這是因為默認日志輸出級別的設置是info,也就是說只有info或它以上的級別被輸出,它以下的級別不被輸出。那如何修改這個設置呢?
日志(Log)的配制:
1.代碼設置
使用setLevel();但這種方式不能改變console的級別,只能改變輸出到文件的日志的級別。
2.修改logging.properties
默認的外部配置文件 是JRE中lib/logging.properties文件。你可以打開這個文件,修改以下兩行為:
.level=ALL
//...
java.util.logging.ConsoleHandler.level = ALL
這種方式會影響jre下所有用戶。
為了不影響到所有的用戶,我們還可以通過LogManager的readConfiguration(InputStream ins)讀取指定的配制文件。
【例1.3】:LogManager管理日志
package lwf.log.test; import java.io.IOException; import java.io.InputStream; import java.util.logging.FileHandler; import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.LogManager; import java.util.logging.LogRecord; import java.util.logging.Logger; import java.util.logging.SimpleFormatter; public class LogTest { static String strClassName = LogTest.class.getName(); static Logger logger = Logger.getLogger(strClassName); static LogManager logManager = LogManager.getLogManager(); static { InputStream inputStream = null; try { //讀取配制文件 inputStream = LogTest.class.getClassLoader().getResourceAsStream("log.properties"); logManager.readConfiguration(inputStream); //添加Logger logManager.addLogger(logger); } catch (SecurityException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } public static double division(int value1, int value2) { double result = 0; try { result = value1 / value2; } catch(ArithmeticException e) { logger.severe("[severe]除數不能為0."); logger.warning("[warning]除數不能為0."); logger.info("[info]除數不能為0."); logger.config("[config]除數不能為0."); logger.fine("[fine]除數不能為0."); logger.finer("[finer]除數不能為0."); logger.finest("[finest]除數不能為0."); e.printStackTrace(); } return result; } public static void main(String[] args) { System.out.println(division(5, 0)); } }
log.properties:
# "handlers" specifies a comma separated list of log Handler
#handlers= java.util.logging.ConsoleHandler
handlers= java.util.logging.FileHandler
# Default logging level.
.level= CONFIG
# default file output is in "E:\Test" directory.
java.util.logging.FileHandler.pattern = E:/Test/Log%u.log
java.util.logging.FileHandler.limit = 50000
java.util.logging.FileHandler.count = 1
java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter
# Limit the message that are printed on the console to CONFIG and above.
java.util.logging.ConsoleHandler.level = CONFIG
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
# Facility specific properties.Provides extra control for each logger.
# For example, set the com.xyz.foo logger to only log SEVERE messages:
com.xyz.foo.level = SEVERE
這樣,用戶就可以自己定義配制文件了。在E:\Test下可以看到輸出的日志文件Log0.log
java.util.logging包中類的關系圖如下:
參考文章:
http://blog.csdn.net/dl88250/article/details/1843813
1.項目串導入log4j的jar包
如Eclipse下項目名右鍵,Build Path\Add Libraries,添加一組用戶自己的jar包。項目結構如下:
2.修改log4j的配制文件,設置日志輸出的級別、格式等
log4j的log有5個級別:FATAL(嚴重的 )、ERROR(錯誤 )、WARN(警告)、INFO(信息)、DEBUG(調試 )。
3.在項目代碼中適當添加日志。
【例2.1】
log4j.properties:
#set log level: show debug, info, error
log4j.rootLogger=DEBUG, A1
# A1 is set to be a ConsoleAppender which outputs to System.out.
#log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1=org.apache.log4j.FileAppender
# A1 uses PatternLayout.
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
#out
log4j.appender.A1.File=E:/test/log4j.log
# set log output format's style
log4j.appender.A1.layout=org.apache.log4j.TTCCLayout
代碼:
package lwf.log.test; import org.apache.log4j.Logger; public class Log4jTest { private static Logger logger = Logger.getLogger(Log4jTest.class); public static void main(String[] args) { System.out.println("This is log4j test."); // 記錄debug級別的信息 logger.debug("This is debug message."); // 記錄info級別的信息 logger.info("This is info message."); // 記錄error級別的信息 logger.error("This is error message."); } }
log4j的使用和配制另參見:http://blog.csdn.net/luoweifu/article/details/43638495
commons-logging提供的是一個日志(Log)接口(interface),是為那些需要建立在不同環境下使用不同日志架構的組件或庫的開發者創建的,其中包括Apache Log4j以及Java log的日志架構。把日志信息抽象成commons-logging的Log接口,並由commons-logging在運行時決定使用哪種日志架構。因為Log4j的強大功能,commons-logging一般會和Log4j一起使用,這幾乎成為了Java日志的標准工具。
commons-logging有兩個基本的抽象類:Log(基本記錄器)和LogFactory(負責創建Log實例)。當commons-logging.jar被加入到CLASSPATH(通常將commons-logging.jar放在web project下的WebContent\WEB-INF\lib目錄中)之後,它會合理地猜測你想用的日志工具,然後進行自我設置,用戶根本不需要做任何設置。默認的LogFactory是按照下列的步驟去發現並決定那個日志工具將被使用的(按照順序,尋找過程會在找到第一個工具時中止,這個順序非常重要):
00001. 尋找當前factory中名叫org.apache.commons.logging.Log配置屬性的值
00002. 尋找系統中屬性中名叫org.apache.commons.logging.Log的值
00003. 如果應用程序的classpath中有log4j,則使用相關的包裝(wrapper)類(Log4JLogger)
00004. 如果應用程序運行在jdk1.4的系統中,使用相關的包裝類(Jdk14Logger)
00005. 使用簡易日志包裝類(SimpleLog)
commons-logging與log4j的配合使用:
項目目錄結構:
common-logging.properties:
#use commons-logging default SimpleLog
# org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog
#use log4j
org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JCategoryLog
#JDK1.4 Logger
#org.apache.commons.logging.Log=org.apache.commons.logging.impl.Jdk14Logger
代碼:
package lwf.log.test; import org.apache.log4j.Logger; public class Log4jTest { private static Logger logger = Logger.getLogger(Log4jTest.class); public static void main(String[] args) { System.out.println("This is log4j test."); // 記錄debug級別的信息 logger.debug("This is debug message."); // 記錄info級別的信息 logger.info("This is info message."); // 記錄error級別的信息 logger.error("This is error message."); } }
參考:
http://www.cnblogs.com/xwdreamer/archive/2011/12/28/2304598.html
http://shift8.iteye.com/blog/1316802
coding....
1.程序錯誤報告
一般應用程序都會在程序發生異常或崩潰時,自動彈出錯誤報告的對話框,用戶可選擇是否提交報告。如果用戶提交錯誤報告,應用程序的開發人員,就可根據報告的日志信息,查看程序出錯的原因,從而更好的改善程序。
2.統計程序的訪問量、使用人數等
雖然這不是一種最好的方式,但也算是一種可行的方式。
1.異常,常常與try...catch...結合使用
2.輸出一此必要的信息,替代命令行的輸出
PS:春節將至,祝大家新年快樂,在新的一年裡更加漂亮,更加健康,更加進步,更加智慧!
如果您有什麼疑惑和想法,請在評論處給予反饋,您的反饋就是最好的測評師!由於本人技術和能力有限,如果本博文有錯誤或不足之處,敬請諒解並給出您寶貴的建議!
========================編程思想系列文章回顧========================
編程思想之異常處理
編程思想之正則表達式
編程思想之迭代器
編程思想之遞歸
編程思想之回調