首頁 後端開發 Python教學 python模組之logging

python模組之logging

Oct 20, 2016 am 11:53 AM

  在現實生活中,記錄日誌非常重要。銀行轉帳時會有轉帳記錄;飛機飛行過程中,會有黑盒子(飛行數據記錄器)記錄飛行過程中的一切。如果有出現什麼問題,人們可以透過日誌資料來搞清楚到底發生了什麼事。對於系統開發、調試以及運行,記錄日誌都是同樣的重要。如果沒有日誌記錄,程式崩潰時你幾乎就沒辦法弄清楚到底發生了什麼事。舉個例子,當你在寫一個伺服器程式時,記錄日誌是非常必要的。下面展示的就是 EZComet.com 伺服器的日誌檔案截圖。

python模組之logging

  服務崩潰後,如果沒有日誌,我幾乎沒辦法知道到底發生了錯誤。日誌不僅對伺服器很重要,對桌面圖形應用同樣十分重要。例如,當你的客戶的 PC 機程式崩潰時,你可以讓他們把日誌檔案寄給你,這樣你就可以找到問題到底出在哪裡。相信我,在不同的 PC 環境下,你永遠不會知道會有什麼奇怪的問題。我曾經就接收過這樣的錯誤日誌。

2011-08-22 17:52:54,828 - root - ERROR - [Errno 10104] getaddrinfo failed
Traceback (most recent call last):
  File "<string>", line 124, in main
  File "<string>", line 20, in __init__
  File "h:workspaceprojectbuildpyi.win32mrdjoutPYZ1.pyz/wx._core", line 7978, in __init__
  File "h:workspaceprojectbuildpyi.win32mrdjoutPYZ1.pyz/wx._core", line 7552, in _BootstrapApp
  File "<string>", line 84, in OnInit
  File "h:workspaceprojectbuildpyi.win32mrdjoutPYZ1.pyz/twisted.internet.wxreactor", line 175, in install
  File "h:workspaceprojectbuildpyi.win32mrdjoutPYZ1.pyz/twisted.internet._threadedselect", line 106, in __init__
  File "h:workspaceprojectbuildpyi.win32mrdjoutPYZ1.pyz/twisted.internet.base", line 488, in __init__
  File "h:workspaceprojectbuildpyi.win32mrdjoutPYZ1.pyz/twisted.internet.posixbase", line 266, in installWaker
  File "h:workspaceprojectbuildpyi.win32mrdjoutPYZ1.pyz/twisted.internet.posixbase", line 74, in __init__
  File "h:workspaceprojectbuildpyi.win32mrdjoutPYZ1.pyz/socket", line 224, in meth
gaierror: [Errno 10104] getaddrinfo failed
登入後複製

  我最終發現,這個客戶的 PC 機被一種病毒感染,導致了呼叫 gethostname 函數失敗。看吧,如果沒有日誌可以檢查你怎麼可能知道這些。

列印輸出不是個好辦法

  儘管記錄日誌非常重要,但是並不是所有的開發者都能正確地使用它。我曾經看過有些開發者是這樣記錄日誌的,在開發的過程中插入 print 語句,開發結束後再移除這些語句。就像這樣:

print &#39;Start reading database&#39;
records = model.read_recrods()
print &#39;# records&#39;, records
print &#39;Updating record ...&#39;
model.update_records(records)
print &#39;done&#39;
登入後複製

  這種方式對於簡單腳本型程式有用,但是如果是複雜的系統,你最好不要使用這樣的方式。首先,你沒辦法做到在日誌檔中只留下極為重要的訊息。你會看到大量的訊息日誌。但是你卻找不到任何有用的資訊。你除了移除這個輸出語句之外,沒別的辦法控製程式碼,但是極有可能的是你忘了移出那些沒用的輸出。再者,print 輸出的所有資訊都到了標準輸出中,這將嚴重影響你從標準輸出中查看其它輸出資料。當然,你也可以把訊息輸出到 stderr ,但用 print 做日誌記錄的方式還是不好。

使用 python 的標準日誌模組

  那麼,怎麼樣記錄日誌才是正確的呢?其實非常簡單,使用 python 的標準日誌模組。多虧 python 社群將日誌做成了一個標準模組。它非常簡單易用且十分靈活。你可以像這樣使用日誌系統:

import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

logger.info(&#39;Start reading database&#39;)
# read database here

records = {&#39;john&#39;: 55, &#39;tom&#39;: 66}
logger.debug(&#39;Records: %s&#39;, records)
logger.info(&#39;Updating records ...&#39;)
# update records here

logger.info(&#39;Finish updating records&#39;)
登入後複製

運行的時候就可看到:

INFO:__main__:Start reading database
INFO:__main__:Updating records ...
INFO:__main__:Finish updating records
登入後複製

你可能會問這與使用 print 有什麼不同呢。它有以下的優勢:

你可以控制訊息的級別,過濾掉那些不重要的訊息。

你可決定輸出到什麼地方,以及怎麼輸出。

  有許多的重要性別等級可供選擇,debug、info、warning、error 以及 critical。透過賦予 logger 或 handler 不同的級別,你就可以只輸出錯誤訊息到特定的記錄檔中,或是在偵錯時只記錄偵錯資訊。讓我們把logger 的等級改成DEBUG 再看一下輸出結果:

 logging.basicConfig(level=logging.DEBUG)
登入後複製

輸出變成了:

INFO:__main__:Start reading database
DEBUG:__main__:Records: {&#39;john&#39;: 55, &#39;tom&#39;: 66}
INFO:__main__:Updating records ...
INFO:__main__:Finish updating records
登入後複製

  正如看到的那樣,我們把logger 的等級改為DEBUG 後,調試記錄就出現在了輸出當中。你也可以選擇怎麼處理這些訊息。例如,你可以使用FileHandler 把記錄寫進文件中:

import logging

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

# create a file handler

handler = logging.FileHandler(&#39;hello.log&#39;)
handler.setLevel(logging.INFO)

# create a logging format

formatter = logging.Formatter(&#39;%(asctime)s - %(name)s - %(levelname)s - %(message)s&#39;)
handler.setFormatter(formatter)

# add the handlers to the logger

logger.addHandler(handler)

logger.info(&#39;Hello baby&#39;)
登入後複製

以合適的等級輸出日誌記錄

  有了靈活的日誌記錄模組後,你可以按適當的等級將日誌記錄輸出到任何地方然後配置它們。那你可能會問,什麼是合適的等級呢?在這兒我將分享一些我的經驗。

大多數的情況下,你不想閱讀日誌中的太多細節。因此,只有你在調試過程中才會使用 DEBUG 等級。我只使用 DEBUG 來獲取詳細的調試信息,特別是當數據量很大或頻率很高的時候,例如演算法內部每個循環的中間狀態。

def complex_algorithm(items):
    for i, item in enumerate(items):
        # do some complex algorithm computation

       logger.debug(&#39;%s iteration, item=%s&#39;, i, item)
登入後複製

在处理请求或者服务器状态变化等日常事务中,我会使用 INFO 等级。

def handle_request(request):
    logger.info(&#39;Handling request %s&#39;, request)
    # handle request here

    result = &#39;result&#39;
    logger.info(&#39;Return result: %s&#39;, result)

def start_service():
    logger.info(&#39;Starting service at port %s ...&#39;, port)
    service.start()
    logger.info(&#39;Service is started&#39;)
登入後複製

当发生很重要的事件,但是并不是错误时,我会使用 WARNING 。比如,当用户登录密码错误时,或者连接变慢时。

def authenticate(user_name, password, ip_address):
     if user_name != USER_NAME and password != PASSWORD:
        logger.warn(&#39;Login attempt to %s from IP %s&#39;, user_name, ip_address)
        return False
    # do authentication here
登入後複製

有错误发生时肯定会使用 ERROR 等级了。比如抛出异常,IO 操作失败或者连接问题等。

def get_user_by_id(user_id):
    user = db.read_user(user_id)
    if user is None:
        logger.error(&#39;Cannot find user with user_id=%s&#39;, user_id)
        return user
    return user
登入後複製

我很少使用 CRITICAL 。当一些特别糟糕的事情发生时,你可以使用这个级别来记录。比方说,内存耗尽,磁盘满了或者核危机(希望永远别发生 :S)。

  虽然不是非得将 logger 的名称设置为 __name__ ,但是这样做会给我们带来诸多益处。在 python 中,变量 __name__ 的名称就是当前模块的名称。比如,在模块 “foo.bar.my_module” 中调用 logger.getLogger(__name__) 等价于调用logger.getLogger(“foo.bar.my_module”) 。当你需要配置 logger 时,你可以配置到 “foo” 中,这样包 foo 中的所有模块都会使用相同的配置。当你在读日志文件的时候,你就能够明白消息到底来自于哪一个模块。

捕捉异常并使用 traceback 记录它

  出问题的时候记录下来是个好习惯,但是如果没有 traceback ,那么它一点儿用也没有。你应该捕获异常并用 traceback 把它们记录下来。比如下面这个例子:

try:
    open(&#39;/path/to/does/not/exist&#39;, &#39;rb&#39;)
except (SystemExit, KeyboardInterrupt):
    raise
except Exception, e:
    logger.error(&#39;Failed to open file&#39;, exc_info=True)
登入後複製

使用参数 exc_info=true 调用 logger 方法, traceback 会输出到 logger 中。你可以看到下面的结果

 ERROR:__main__:Failed to open file
 Traceback (most recent call last):
   File "example.py", line 6, in <module>
    open(&#39;/path/to/does/not/exist&#39;, &#39;rb&#39;)
 IOError: [Errno 2] No such file or directory: &#39;/path/to/does/not/exist&#39;
登入後複製

Python 使用logging模块记录日志涉及四个主要类,使用官方文档中的概括最为合适:

logger提供了应用程序可以直接使用的接口;

handler将(logger创建的)日志记录发送到合适的目的输出;

filter提供了细度设备来决定输出哪条日志记录;

formatter决定日志记录的最终输出格式。

logging模块是在2.3新引进的功能,下面是一些常用的类和模块级函数

模块级函数
logging.getLogger([name]):返回一个logger对象,如果没有指定名字将返回root logger
logging.debug()、logging.info()、logging.warning()、logging.error()、logging.critical():设定root logger的日志级别
logging.basicConfig():用默认Formatter为日志系统建立一个StreamHandler,设置基础配置并加到root logger中

python模組之logging

每个程序在输出信息之前都要获得一个Logger。Logger通常对应了程序的模块名,比如聊天工具的图形界面模块可以这样获得它的Logger:
LOG=logging.getLogger(”chat.gui”)
而核心模块可以这样:
LOG=logging.getLogger(”chat.kernel”)

Logger.setLevel(lel):指定最低的日志级别,低于lel的级别将被忽略。debug是最低的内置级别,critical为最高
Logger.addFilter(filt)、Logger.removeFilter(filt):添加或删除指定的filter
Logger.addHandler(hdlr)、Logger.removeHandler(hdlr):增加或删除指定的handler
Logger.debug()、Logger.info()、Logger.warning()、Logger.error()、Logger.critical():可以设置的日志级别
设置logger的level, level有以下几个级别:

python模組之logging

NOTSET < DEBUG < INFO < WARNING < ERROR < CRITICAL
如果把looger的级别设置为INFO, 那么小于INFO级别的日志都不输出, 大于等于INFO级别的日志都输出

Handlers
handler对象负责发送相关的信息到指定目的地。Python的日志系统有多种Handler可以使用。有些Handler可以把信息输出到控制台,有些Logger可以把信息输出到文件,还有些 Handler可以把信息发送到网络上。如果觉得不够用,还可以编写自己的Handler。可以通过addHandler()方法添加多个多handler
Handler.setLevel(lel):指定被处理的信息级别,低于lel级别的信息将被忽略
Handler.setFormatter():给这个handler选择一个格式
Handler.addFilter(filt)、Handler.removeFilter(filt):新增或删除一个filter对象

Formatters

Formatter对象设置日志信息最后的规则、结构和内容,默认的时间格式为%Y-%m-%d %H:%M:%S,下面是Formatter常用的一些信息

python模組之logging

设置过滤器
细心的朋友一定会发现前文调用logging.getLogger()时参数的格式类似于“A.B.C”。采取这样的格式其实就是为了可以配置过滤器。看一下这段代码:
LOG=logging.getLogger(”chat.gui.statistic”)
console = logging.StreamHandler()
console.setLevel(logging.INFO)
formatter = logging.Formatter(’%(asctime)s %(levelname)s %(message)s’)
console.setFormatter(formatter)
filter=logging.Filter(”chat.gui”)
console.addFilter(filter)
LOG.addHandler(console)
和前面不同的是我们在Handler上添加了一个过滤器。现在我们输出日志信息的时候就会经过过滤器的处理。名为“A.B”的过滤器只让名字带有 “A.B”前缀的Logger输出信息。可以添加多个过滤器,只要有一个过滤器拒绝,日志信息就不会被输出。当然名为“A”前缀的Logger会输出信息。另外,在Logger中也可以添加过滤器。

每个Logger可以附加多个Handler。接下来我们就来介绍一些常用的Handler:
1) logging.StreamHandler
使用这个Handler可以向类似与sys.stdout或者sys.stderr的任何文件对象(file object)输出信息。它的构造函数是:
StreamHandler([strm])
其中strm参数是一个文件对象。默认是sys.stderr
2) logging.FileHandler
和StreamHandler类似,用于向一个文件输出日志信息。不过FileHandler会帮你打开这个文件。它的构造函数是:
FileHandler(filename[,mode])
filename是文件名,必须指定一个文件名。
mode是文件的打开方式。参见Python内置函数open()的用法。默认是’a',即添加到文件末尾。
3) logging.handlers.RotatingFileHandler
这个Handler类似于上面的FileHandler,但是它可以管理文件大小。当文件达到一定大小之后,它会自动将当前日志文件改名,然后创建 一个新的同名日志文件继续输出。比如日志文件是chat.log。当chat.log达到指定的大小之后,RotatingFileHandler自动把 文件改名为chat.log.1。不过,如果chat.log.1已经存在,会先把chat.log.1重命名为chat.log.2。。。最后重新创建 chat.log,继续输出日志信息。它的构造函数是:
RotatingFileHandler( filename[, mode[, maxBytes[, backupCount]]])
其中filename和mode两个参数和FileHandler一样。
maxBytes用于指定日志文件的最大文件大小。如果maxBytes为0,意味着日志文件可以无限大,这时上面描述的重命名过程就不会发生。
backupCount用于指定保留的备份文件的个数。比如,如果指定为2,当上面描述的重命名过程发生时,原有的chat.log.2并不会被更名,而是被删除。
4) logging.handlers.TimedRotatingFileHandler
这个Handler和RotatingFileHandler类似,不过,它没有通过判断文件大小来决定何时重新创建日志文件,而是间隔一定时间就 自动创建新的日志文件。重命名的过程与RotatingFileHandler类似,不过新的文件不是附加数字,而是当前时间。它的构造函数是:
TimedRotatingFileHandler( filename [,when [,interval [,backupCount]]])
其中filename参数和backupCount参数和RotatingFileHandler具有相同的意义。
interval是时间间隔。
when参数是一个字符串。表示时间间隔的单位,不区分大小写。它有以下取值:
S 秒
M 分
H 小时
D 天
W 每星期(interval==0时代表星期一)
midnight 每天凌晨
5) logging.handlers.SocketHandler
6) logging.handlers.DatagramHandler
以上两个Handler类似,都是将日志信息发送到网络。不同的是前者使用TCP协议,后者使用UDP协议。它们的构造函数是:
Handler(host, port)
其中host是主机名,port是端口名
7) logging.handlers.SysLogHandler
8) logging.handlers.NTEventLogHandler
9) logging.handlers.SMTPHandler
10) logging.handlers.MemoryHandler
11) logging.handlers.HTTPHandler

# encoding:utf-8
#import logging

#FORMAT = &#39;%(asctime)-15s %(clientip)s %(user)-8s %(message)s&#39;
#logging.basicConfig(format=FORMAT)
#d = {&#39;clientip&#39;: &#39;192.168.0.1&#39;, &#39;user&#39;: &#39;fbloggs&#39;}
#logger = logging.getLogger(&#39;tcpserver&#39;)
#logger.warning(&#39;Protocol problem: %s&#39;, &#39;connection reset&#39;, extra=d)

#FORMAT = &#39;%(asctime)-15s %(message)s&#39;
#logging.basicConfig(filename = "C:\\Users\\june\\Desktop\\1.txt", level = logging.DEBUG, filemode = "a", format=FORMAT)  
#logging.debug(&#39;this is a message&#39;)  
#logging.debug(&#39;test&#39;)  

#import logging
#import datetime
#
#curDate = datetime.date.today() - datetime.timedelta(days=0)
#logName =  &#39;C:\\Users\\june\\Desktop\\error_%s.log&#39; %curDate
#
#logging.basicConfig(level=logging.INFO,
#                format=&#39;%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s&#39;,
#                #datefmt=&#39;%a, %d %b %Y %H:%M:%S&#39;,
#                filename=logName,
#                filemode=&#39;a&#39;)
#
##2013-10-21 03:25:51,509 writeLog.py[line:14] INFO This is info message
##2013-10-21 03:25:51,510 writeLog.py[line:15] WARNING This is warning message
#logging.debug(&#39;This is debug message&#39;)
#logging.info(&#39;This is info message&#39;)
#logging.warning(&#39;This is warning message&#39;)import logging
import logging.config

logging.config.fileConfig("logging.conf")

#create logger
loggerInfo = logging.getLogger("infoLogger")

#"application" code
loggerInfo.debug("debug message")
loggerInfo.info("info message")
loggerInfo.warn("warn message")
loggerInfo.error("error message")
loggerInfo.critical("critical message")


loggerError = logging.getLogger("errorLogger")
loggerError.error("Error: Hello world!")
登入後複製
#coding=utf-8
import logging
import datetime

format=&#39;%(asctime)s - %(filename)s - [line:%(lineno)d] - %(levelname)s - %(message)s&#39;
curDate = datetime.date.today() - datetime.timedelta(days=0)
infoLogName =  r&#39;C:/Users/june/Desktop/info_%s.log&#39; %curDate
errorLogName =  r&#39;C:/Users/june/Desktop/error_%s.log&#39; %curDate

formatter = logging.Formatter(format)

infoLogger = logging.getLogger("infoLog")
errorLogger = logging.getLogger("errorLog")

infoLogger.setLevel(logging.INFO)
errorLogger.setLevel(logging.ERROR)

infoHandler = logging.FileHandler(infoLogName, &#39;a&#39;)
infoHandler.setLevel(logging.INFO)
infoHandler.setFormatter(formatter)

errorHandler = logging.FileHandler(errorLogName, &#39;a&#39;)
errorHandler.setLevel(logging.ERROR)
errorHandler.setFormatter(formatter)

testHandler = logging.StreamHandler()
testHandler.setFormatter(formatter)
testHandler.setLevel(logging.ERROR)

infoLogger.addHandler(infoHandler)
infoLogger.addHandler(testHandler)
errorLogger.addHandler(errorHandler)

#infoLogger.debug("debug message")
#infoLogger.info("info message")
#infoLogger.warn("warn message")
# # 下面这行会同时打印在文件和终端上
#infoLogger.error("error message")
#
#errorLogger.error("error message")
#errorLogger.critical("critical message")
登入後複製
&#39;&#39;&#39;
Created on 2016年8月18日

@author: apple
&#39;&#39;&#39;
#-*- coding:utf-8 -*-

#开发出一个日志系统,既要把日志输出到控制台,还要写入日志文件

import logging
import time
import os
import os.path

class Logger():
    def __init__(self, log_name, logger_name):
        
        &#39;&#39;&#39;
                指定保存日志的文件路径,日志级别以及调用文件
                将日志    存入到指定的文件中
    
        &#39;&#39;&#39;
        #设置日志文件名称:time.time()取得当前时间;time.localtime()取得本地时间;time.strftime()格式化日期;
        time_str = time.strftime("%Y_%m_%d_%H_%M_%S", time.localtime(time.time()))
        logname = time_str + &#39;_&#39; + log_name + &#39;.log&#39;
        
        #设置日志文件所在的路径
        log_filedir = &#39;Log&#39;
        if not os.path.isdir(log_filedir):
            print("日志文件夹 %s 不存在,开始创建此文件夹" %log_filedir)
            os.mkdir(&#39;Log&#39;)
        else:
            print("日志文件夹 %s 存在" %log_filedir)
        
        os.chdir(&#39;Log&#39;)
        
        #创建一个logger以及设置日志级别
        #logging有6个日志级别:NOTSET, DEBUG, INFO, WARNING, ERROR, CRITICAL对应的值分别为:0,10,20,30,40,50
        #例如:logging.DEBUG和10是等价的表示方法
        #可以给日志对象(Logger Instance)设置日志级别,低于该级别的日志消息将会被忽略,也可以给Hanlder设置日志级别
        #对于低于该级别的日志消息, Handler也会忽略。
        self.logger = logging.getLogger(logger_name)
        self.logger.setLevel(logging.DEBUG)
        
        #创建文件handler,用于写入日志文件并设置文件日志级别
        file_handler = logging.FileHandler(logname)
        file_handler.setLevel(logging.DEBUG)
        
        #创建控制端输出handler,用于输出到控制端并设置输出日志级别
        console_handler = logging.StreamHandler()
        console_handler.setLevel(logging.DEBUG)
        
        #在控制端handler添加过滤器,将含有chat或者gui的handler信息输出
        filter = logging.Filter("chat.gui")
        console_handler.addFilter(filter)
        
        #定义handler的输出格式并将格式应用到handler
        formatter = logging.Formatter(&#39;%(asctime)s-%(name)s-%(levelname)s-%(message)s&#39;)
        file_handler.setFormatter(formatter)
        console_handler.setFormatter(formatter)
        
        #将handler加入到logger
        self.logger.addHandler(file_handler)
        self.logger.addHandler(console_handler)
        
        self.logger.debug("这个是debug日志信息")
        self.logger.info("欢迎大家来到 Python的世界")
        
        
        #将handler从logger中移除
        self.logger.removeHandler(file_handler)
        self.logger.removeHandler(console_handler)

if __name__ == &#39;__main__&#39;:       
    print(os.getcwd())
    Log = Logger(&#39;create_log&#39;, "chat.gui.statistic")
        


# 模块级函数
# 
# logging.getLogger([name]):返回一个logger对象,如果没有指定名字将返回root logger
# logging.debug()、logging.info()、logging.warning()、logging.error()、logging.critical():设定root logger的日志级别
# logging.basicConfig():用默认Formatter为日志系统建立一个StreamHandler,设置基础配置并加到root logger中
# 
# Loggers
# 
# Logger.setLevel(lel):指定最低的日志级别,低于lel的级别将被忽略。debug是最低的内置级别,critical为最高
# Logger.addFilter(filt)、Logger.removeFilter(filt):添加或删除指定的filter
# Logger.addHandler(hdlr)、Logger.removeHandler(hdlr):增加或删除指定的handler
# Logger.debug()、Logger.info()、Logger.warning()、Logger.error()、Logger.critical():可以设置的日志级别

# Handlers
# 
# handler对象负责发送相关的信息到指定目的地。可以通过addHandler()方法添加多个多handler
# Handler.setLevel(lel):指定被处理的信息级别,低于lel级别的信息将被忽略
# Handler.setFormatter():给这个handler选择一个格式
# Handler.addFilter(filt)、Handler.removeFilter(filt):新增或删除一个filter对象

# Formatters
# 
# Formatter对象设置日志信息最后的规则、结构和内容,默认的时间格式为%Y-%m-%d %H:%M:%S,下面是Formatter常用的一些信息


# %(name)s                       Logger的名字
#  
# %(levelno)s                    数字形式的日志级别
#  
# %(levelname)s                文本形式的日志级别
#  
# %(pathname)s                调用日志输出函数的模块的完整路径名,可能没有
# 
# %(filename)s                  调用日志输出函数的模块的文件名
#  
# %(module)s                    调用日志输出函数的模块名
#  
# %(funcName)s                调用日志输出函数的函数名
#  
# %(lineno)d                     调用日志输出函数的语句所在的代码行
#  
# %(created)f                    当前时间,用UNIX标准的表示时间的浮 点数表示
#  
# %(relativeCreated)d        输出日志信息时的,自Logger创建以 来的毫秒数
#  
# %(asctime)s                  字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
# 
# %(thread)d                   线程ID。可能没有
# 
# %(threadName)s           线程名。可能没有
# 
# %(process)d                 进程ID。可能没有
#  
# %(message)s               用户输出的消息
登入後複製
&#39;&#39;&#39;
Created on 2016年8月25日

@author: apple
&#39;&#39;&#39;
import logging

logging.basicConfig(level=logging.INFO,
                    format=&#39;%(asctime)s %(name)s %(levelname)s %(message)s&#39;,
                    datefmt=&#39;%m-%d %H:%M&#39;,
                    filename=&#39;./AutoUpdate.log&#39;,
                    filemode=&#39;w&#39;)

console = logging.StreamHandler()
console.setLevel(logging.INFO)
formatter = logging.Formatter(&#39;%(name)s: %(levelname)-8s %(message)s&#39;)
console.setFormatter(formatter)
logging.getLogger(&#39;&#39;).addHandler(console)

logging.info("hello world!")
登入後複製


本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1668
14
CakePHP 教程
1427
52
Laravel 教程
1329
25
PHP教程
1273
29
C# 教程
1256
24
Python:遊戲,Guis等 Python:遊戲,Guis等 Apr 13, 2025 am 12:14 AM

Python在遊戲和GUI開發中表現出色。 1)遊戲開發使用Pygame,提供繪圖、音頻等功能,適合創建2D遊戲。 2)GUI開發可選擇Tkinter或PyQt,Tkinter簡單易用,PyQt功能豐富,適合專業開發。

Python與C:學習曲線和易用性 Python與C:學習曲線和易用性 Apr 19, 2025 am 12:20 AM

Python更易學且易用,C 則更強大但複雜。 1.Python語法簡潔,適合初學者,動態類型和自動內存管理使其易用,但可能導致運行時錯誤。 2.C 提供低級控制和高級特性,適合高性能應用,但學習門檻高,需手動管理內存和類型安全。

Python和時間:充分利用您的學習時間 Python和時間:充分利用您的學習時間 Apr 14, 2025 am 12:02 AM

要在有限的時間內最大化學習Python的效率,可以使用Python的datetime、time和schedule模塊。 1.datetime模塊用於記錄和規劃學習時間。 2.time模塊幫助設置學習和休息時間。 3.schedule模塊自動化安排每週學習任務。

Python vs.C:探索性能和效率 Python vs.C:探索性能和效率 Apr 18, 2025 am 12:20 AM

Python在開發效率上優於C ,但C 在執行性能上更高。 1.Python的簡潔語法和豐富庫提高開發效率。 2.C 的編譯型特性和硬件控制提升執行性能。選擇時需根據項目需求權衡開發速度與執行效率。

Python標準庫的哪一部分是:列表或數組? Python標準庫的哪一部分是:列表或數組? Apr 27, 2025 am 12:03 AM

pythonlistsarepartofthestAndArdLibrary,herilearRaysarenot.listsarebuilt-In,多功能,和Rused ForStoringCollections,而EasaraySaraySaraySaraysaraySaraySaraysaraySaraysarrayModuleandleandleandlesscommonlyusedDduetolimitedFunctionalityFunctionalityFunctionality。

Python:自動化,腳本和任務管理 Python:自動化,腳本和任務管理 Apr 16, 2025 am 12:14 AM

Python在自動化、腳本編寫和任務管理中表現出色。 1)自動化:通過標準庫如os、shutil實現文件備份。 2)腳本編寫:使用psutil庫監控系統資源。 3)任務管理:利用schedule庫調度任務。 Python的易用性和豐富庫支持使其在這些領域中成為首選工具。

學習Python:2小時的每日學習是否足夠? 學習Python:2小時的每日學習是否足夠? Apr 18, 2025 am 12:22 AM

每天學習Python兩個小時是否足夠?這取決於你的目標和學習方法。 1)制定清晰的學習計劃,2)選擇合適的學習資源和方法,3)動手實踐和復習鞏固,可以在這段時間內逐步掌握Python的基本知識和高級功能。

Python vs. C:了解關鍵差異 Python vs. C:了解關鍵差異 Apr 21, 2025 am 12:18 AM

Python和C 各有優勢,選擇應基於項目需求。 1)Python適合快速開發和數據處理,因其簡潔語法和動態類型。 2)C 適用於高性能和系統編程,因其靜態類型和手動內存管理。

See all articles