如何正確使用日志Log


title: 如何正確使用日志Log
date: 2015-01-08 12:54:46
categories: [Python]
tags: [Python,log]

文章首發地址:http://kingname.info

這篇文章不會教你在技術角度上使用log,而是告訴你為什么要使用log日志功能。

為什么要使用Log

使用微信控制你的電腦這篇文章中,我寫好了電腦端的程序,使用py2exe生成可執行文件,並把它們發送給我的朋友讓他們進行測試。但是他們把_config.ini設置好以后,運行程序就看到一個黑色窗口一閃而過。或者有些人一開始看到程序能正常登陸郵箱,但是准備執行命令的時候,窗口自動關閉。

由於沒有日志記錄程序的運行狀態,我根據他們的描述很難定位到錯誤在哪個地方。於是折騰了一個下午。

這個時候,我覺得添加一個日志的功能迫在眉睫。

哪些地方應該用Log

目前網上能找到的關於如何使用日志的文章,全部都是從技術角度講怎么使用log:在XX地方應該先imort logging,然后basicconfig設定XX內容。可是我現在的問題是:

  • 應該在程序的哪些地方添加日志的輸出?
  • 輸出什么內容?
  • 如何輸出才能以方便我的監控程序的運行情況?

於是我只有自己摸索。因此,以下內容是我自己摸索出來的野路子,可能會有錯漏。希望有經驗的朋友能給我指正,非常感謝。

這些地方應該用Log

使用使用微信控制你的電腦文章中涉及到的例子

程序入口代碼如下:

if __name__=='__main__':
        init()
        print u'等待接收命令'
        logging.info(u'初始化完成。')
        while 1:
                time.sleep(int(time_limit)) #每5分鍾檢查一次郵箱
                accp_mail()

以上代碼表示程序運行以后,首先執行init()函數,於是如果init()初始化沒有什么問題,成功執行完成以后,就應該在日志中輸出“初始化完成”,然后進入接收郵件的循環。如果程序窗口運行以后一閃而過,而且生成的日志中沒有初始化完成這樣的字眼,那就說明問題出在初始化上面。

然而初始化函數里面代碼也有很多,又如何知道是初始化程序里面的什么地方出問題了呢?

所以,再初始化函數里面,也應該有一定的日志記錄。

再看初始化函數的代碼:

def init():
        global username,password,host,boss_email,time_limit
      	 
		try:
            f = open('_config.ini','r')
    	except IOError,e:
            logging.error(e)
			exit()

        info = f.readlines()
		try:
	        host = re.search('host:(.*?)\n',info[0],re.S).group(1)
	        username = re.search('username:(.*?com)',info[1],re.S).group(1)
	        password = re.search('password:(.*?)\n',info[2],re.S).group(1)
	        boss_email = re.search('boss_email:(.*?com)',info[3],re.S).group(1)
	        time_limit = re.search('time_limit:(.*?)\n',info[4],re.S).group(1)
		except Exception,e:
            logging.error(e)

        logging.info(u'打開配置文件成功。。。')
		

        #將命令生成字典,便於查詢
        command_start = info.index('<command>\n')
        command_end = info.index('</command>\n')
        for each in info[command_start+1:command_end]:
                command = each.split('=')
                command_dict[command[0]] = command[1]
		
        logging.info(command_dict)
		
        open_start = info.index('<open_file>\n')
        open_end = info.index('</open_file>\n')
        for each in info[open_start+1:open_end]:
                open_file = each.split('=')
                open_dict[open_file[0]] = open_file[1][:-1]
		
        logging.info(open_dict)
		
        f.close()

在這段代碼中,我使用try except命令捕獲異常,如果發生異常,就使用logging.error將錯誤寫入日志中。例如當_config.ini被改名了或者被刪除的時候,程序就會報錯,而通過日志就能發現這個錯誤。

經過上面的代碼,如果在初始化的過程中出錯,就可以很快確定問題出在什么地方。

初始化完成以后,進入郵件接收階段。

def accp_mail():
        logging.info(u'開始檢查郵箱')
		try:
	        pp = poplib.POP3_SSL(host)
	        pp.set_debuglevel(1)
	        pp.user(username)
	        pp.pass_(password)
	        ret = pp.list()
	        logging.info(u'登錄郵箱成功。')
		except Exception,e:
			logging.error(e)
			exit()
		
		logging.info(u'開始抓取郵件。')
		try:
        	down = pp.retr(len(ret[1]))
			logging.info(u抓取郵件成功。'')
		except Exception,e:
			logging.error(e)
			exit()

		logging.info(u'開始抓取subject和發件人')
        try:
            subject = re.search("Subject: (.*?)',",str(down[1]).decode('utf-8'),re.S).group(1)
            sender = re.search("'X-Sender: (.*?)',",str(down[1]).decode('utf-8'),re.S).group(1)
            logging.info(u'抓取subject和發件人成功')
    	except Exception,e:
            logging.error(e)
            exit()

        if subject != 'pass':
                if sender == boss_email:
                        DealCommand(subject)
        pp.quit()

以上這段代碼,對郵箱的登錄與郵件的讀取均作了監控,一旦有某個環節出了問題,就會體現在日志中。

通過在登錄環節的try except返回的錯誤日志,發現有很多朋友無法登錄郵箱,而密碼用戶名都沒有錯,從而推斷是沒有在新浪郵箱的賬戶控制里面打開客服端接收POP3和SMTP的功能。

再來看DealCommand()函數:

def DealCommand(subject):
        logging.info(u'開始處理命令。')
        send_mail('pass','slave')
        if subject in command_dict:
                logging.info(u'執行命令')
                try:
                        command = command_dict[subject]
                        os.system(command)
                        send_mail('Success','boss')
                        logging.info(u'執行命令成功')
                except Exception,e:
                        logging.error(e)
                        send_mail('error','boss',e)
        elif subject in open_dict:
                logging.info(u'打開文件')
                try:
                        open_file = open_dict[subject]
                        win32api.ShellExecute(0, 'open', open_file, '','',1)
                        send_mail('Success','boss')
                        logging.info(u'打開文件成功')
                except Exception,e:
                        logging.error(e)
                        send_mail('error','boss',e)
        else:
                send_mail('error','boss','no such command')

執行命令的地方可能會出錯,於是果斷使用try except捕獲錯誤。並使用日志記錄。

最后是send_mail()函數:

def send_mail(subject,flag,body='Success'):
        
        msg = MIMEText(body,'plain','utf-8')#中文需參數‘utf-8’,單字節字符不需要
        msg['Subject'] = subject
        msg['from'] = username
        logging.info('開始配置發件箱。')
        try:
                handle = smtplib.SMTP('smtp.sina.com', 25)
                handle.login(username,password)
                logging.info('發件箱配置成功')
        except Exception,e:
                logging.error(e)
                exit()

        logging.info(u'開始發送郵件'+ 'to' + flag)
        if flag == 'slave':
                try:
                        handle.sendmail(username,username, msg.as_string())
                        logging.info(u'發送郵件成功')
                except Exception,e:
                        logging.error(e)
                        exit()
        elif flag == 'boss':
                try:
                        handle.sendmail(username,boss_email, msg.as_string())
                        logging.info(u'發送郵件成功')
                except Exception,e:
                        logging.error(e)
                        exit()
                
        handle.close()
        logging.info(u'發送郵件結束'+flag)

這里對郵件發件的部分需要特別仔細的錯誤捕獲,然后記錄進入日志中。

完整的代碼見:https://github.com/kingname/MCC.git中的auto.py

總結

需要使用日志記錄的地方大致有一下幾處:

  • 所有輸入輸出處,無論是從文件輸入還是從網絡等其他地方輸入
  • 執行命令處
  • 調用函數處

PS

這里我對一般信息的記錄使用了info,實際上,一般用作調試的話,是使用debug更多。

需要用戶輸入的地方,總會有想不到的錯誤,多小心都不為過。例如,用戶可能會把time_limit設定為一個全角數字。而本文中就沒有捕獲這種問題到日志中。所以如果不放心的話,還可以更進一步的細化日志。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM