เมื่อแอปพลิเคชันมีความซับซ้อนมากขึ้นการมี ดี บันทึกจะมีประโยชน์มากไม่เพียง แต่เมื่อทำการดีบั๊กเท่านั้น แต่ยังให้ข้อมูลเชิงลึกสำหรับปัญหา / ประสิทธิภาพของแอปพลิเคชันด้วย
ไลบรารีมาตรฐาน Python มาพร้อมกับไฟล์ การบันทึก โมดูลที่มีคุณสมบัติการบันทึกพื้นฐานส่วนใหญ่ ด้วยการตั้งค่าอย่างถูกต้องข้อความบันทึกสามารถให้ข้อมูลที่เป็นประโยชน์มากมายเกี่ยวกับเวลาและสถานที่ที่บันทึกถูกเริ่มทำงานตลอดจนบริบทของบันทึกเช่นกระบวนการ / เธรดที่กำลังทำงานอยู่
แม้จะมีข้อดี แต่โมดูลการบันทึกมักถูกมองข้ามเนื่องจากต้องใช้เวลาพอสมควรในการตั้งค่าอย่างถูกต้องและแม้ว่าจะเสร็จสมบูรณ์แล้วก็ตามในความคิดของฉันเอกสารการบันทึกอย่างเป็นทางการที่ https://docs.python.org/3/library/logging.html ไม่ได้ให้แนวทางปฏิบัติที่ดีที่สุดในการบันทึกหรือเน้นความประหลาดใจในการบันทึก
บทแนะนำการบันทึก Python นี้ไม่ได้หมายถึงเอกสารที่สมบูรณ์ในโมดูลการบันทึก แต่เป็นคำแนะนำในการ 'เริ่มต้นใช้งาน' ที่แนะนำแนวคิดการบันทึกบางอย่างรวมถึง 'gotcha' ที่ต้องระวัง โพสต์จะจบลงด้วยแนวทางปฏิบัติที่ดีที่สุดและมีคำแนะนำสำหรับหัวข้อการบันทึกขั้นสูงเพิ่มเติม
โปรดทราบว่าข้อมูลโค้ดทั้งหมดในโพสต์สมมติว่าคุณได้นำเข้าโมดูลการบันทึกแล้ว:
import logging
ส่วนนี้จะให้ภาพรวมเกี่ยวกับแนวคิดบางอย่างที่มักพบในโมดูลการบันทึก
ระดับบันทึกสอดคล้องกับ 'ความสำคัญ' ที่บันทึก: บันทึก 'ข้อผิดพลาด' ควรเป็นข้อมูลเร่งด่วนมากกว่าบันทึก 'เตือน' ในขณะที่บันทึก 'แก้ไขข้อบกพร่อง' ควรมีประโยชน์เฉพาะเมื่อทำการดีบักแอปพลิเคชัน
มีหกระดับการบันทึกใน Python; แต่ละระดับเชื่อมโยงกับจำนวนเต็มที่ระบุความรุนแรงของบันทึก: NOTSET = 0, DEBUG = 10, INFO = 20, WARN = 30, ERROR = 40 และ CRITICAL = 50
ทุกระดับค่อนข้างตรงไปตรงมา (DEBUG โดยทั่วไปแล้วตัวจัดรูปแบบบันทึกจะเสริมสร้างข้อความบันทึกโดยการเพิ่มข้อมูลบริบทเข้าไป การทราบว่ามีการส่งบันทึกเมื่อใดที่ (ไฟล์ Python หมายเลขบรรทัดวิธีการ ฯลฯ ) และบริบทเพิ่มเติมเช่นเธรดและกระบวนการ (จะมีประโยชน์อย่างยิ่งเมื่อทำการดีบักแอปพลิเคชันแบบมัลติเธรด) ตัวอย่างเช่นเมื่อบันทึก“ สวัสดีชาวโลก” ถูกส่งผ่านตัวจัดรูปแบบบันทึก: มันจะกลายเป็น ตัวจัดการบันทึกเป็นส่วนประกอบที่เขียน / แสดงบันทึกได้อย่างมีประสิทธิภาพ: แสดงในคอนโซล (ผ่าน StreamHandler) ในไฟล์ (ผ่าน FileHandler) หรือแม้กระทั่งการส่งอีเมลถึงคุณผ่าน SMTPHandler เป็นต้น ตัวจัดการบันทึกแต่ละรายการมี 2 ฟิลด์ที่สำคัญ: ไลบรารีมาตรฐานมีตัวจัดการจำนวนหนึ่งที่ควรเพียงพอสำหรับกรณีการใช้งานทั่วไป: https://docs.python.org/3/library/logging.handlers.html#module-logging.handlers . สิ่งที่พบบ่อยที่สุดคือ StreamHandler และ FileHandler: Logger น่าจะเป็นคนที่ถูกใช้โดยตรงบ่อยที่สุดในโค้ดและเป็นรหัสที่ซับซ้อนที่สุด สามารถรับคนตัดไม้ใหม่ได้โดย: คนตัดไม้มีสามช่องหลัก: คนตัดไม้คือ ไม่เหมือนใคร ตามชื่อหมายความว่าหากมีการสร้างคนตัดไม้ที่มีชื่อว่า 'toto' การเรียกที่ตามมาของ อย่างที่คุณอาจเดาได้ว่าคนตัดไม้มีลำดับชั้น ด้านบนของลำดับชั้นคือ root logger ซึ่งสามารถเข้าถึงได้ผ่าน logging.root คนตัดไม้นี้ถูกเรียกเมื่อเมธอดเช่น ตามค่าเริ่มต้นเมื่อสร้างคนตัดไม้ใหม่แม่ของมันจะถูกตั้งค่าเป็น root logger: อย่างไรก็ตามคนตัดไม้ใช้“ สัญลักษณ์จุด” ซึ่งหมายความว่าคนตัดไม้ที่มีชื่อ“ a.b” จะเป็นลูกของคนตัดไม้“ ก.” อย่างไรก็ตามนี่จะเป็นจริงก็ต่อเมื่อมีการสร้างคนตัดไม้“ a” มิฉะนั้นพาเรนต์“ ab” ยังคงเป็นรูท เมื่อคนตัดไม้ตัดสินใจว่าควรส่งบันทึกตามการตรวจสอบระดับหรือไม่ (เช่นหากระดับการบันทึกต่ำกว่าระดับคนตัดไม้บันทึกจะถูกละเว้น) จะใช้ 'ระดับประสิทธิภาพ' แทนระดับจริง ระดับที่มีประสิทธิภาพจะเหมือนกับระดับคนตัดไม้หากระดับนั้นไม่ใช่ NOTSET นั่นคือค่าทั้งหมดตั้งแต่ดีบักจนถึงระดับคริติคอล อย่างไรก็ตามหากระดับคนตัดไม้ไม่ได้ตั้งค่าระดับที่มีประสิทธิภาพจะเป็นระดับบรรพบุรุษแรกที่มีระดับที่ไม่ใช่ NOTSET โดยค่าเริ่มต้นคนตัดไม้ใหม่จะมีระดับ NOTSET และเนื่องจากคนตัดไม้รูทมีระดับ WARN ระดับประสิทธิภาพของคนตัดไม้จะเป็น WARN ดังนั้นแม้ว่าคนตัดไม้ใหม่จะมีตัวจัดการบางตัวติดอยู่ตัวจัดการเหล่านี้จะไม่ถูกเรียกเว้นแต่ระดับการบันทึกจะเกิน WARN: โดยค่าเริ่มต้นระดับคนตัดไม้จะถูกใช้เพื่อตัดสินใจว่าจะผ่านบันทึก: ถ้าระดับการบันทึกต่ำกว่าระดับคนบันทึกระบบจะไม่สนใจ โมดูลการบันทึกนั้นมีประโยชน์มาก แต่ก็มีนิสัยแปลก ๆ บางอย่างที่อาจทำให้ปวดหัวเป็นเวลานานได้ Python นักพัฒนา นี่คือแนวทางปฏิบัติที่ดีที่สุดสำหรับการใช้โมดูลนี้ในความคิดของฉัน: หลังจากสร้างคนตัดไม้ใหม่และใช้งานได้แล้ว: หากคุณสนใจแนวทางปฏิบัติที่ดีที่สุดเพิ่มเติมโปรดอ่าน 10 ข้อผิดพลาดที่พบบ่อยที่สุดที่นักพัฒนา Python ทำ โดยเพื่อน ApeeScapeer Martin Chikilian เครื่องมือดีบักคือเครื่องมือที่ช่วยให้นักพัฒนาสามารถตรวจจับข้อผิดพลาดและตรวจสอบปัญหาได้ อาจเป็นเครื่องมือบรรทัดคำสั่งเช่น gdb, pdb (สำหรับ Python) หรือสามารถฝังใน IDE (Visual Studio, ชุดความคิด ฯลฯ ) นี่เป็นเพียงผลลัพธ์ของโปรแกรมซึ่งเป็น 'การพิมพ์' เวอร์ชันที่ดีกว่าในแง่ของคนธรรมดา ในบริบทของเว็บแอปพลิเคชันบันทึกนี้มักจะมีข้อมูลการร้องขอที่เข้ามาเช่นเส้นทางการร้องขอเวลาขอสถานะ HTTP เป็นต้น การบันทึกเป็นโมดูลในไลบรารีมาตรฐาน Python ที่จัดเตรียมบันทึกที่มีรูปแบบสมบูรณ์พร้อมตัวกรองที่ยืดหยุ่นและความเป็นไปได้ในการเปลี่ยนเส้นทางบันทึกไปยังแหล่งอื่นเช่น syslog หรืออีเมล python debugger ที่นิยมมากที่สุดคือ pdb ขณะนี้มีบางโครงการที่ทำงานเพื่อปรับปรุงการใช้งานของ pdb โดยการจัดเตรียมการเติมแท็บไวยากรณ์สีการเรียกดูโค้ดหรือการดีบักระยะไกล โครงการเหล่านี้ ได้แก่ ipdb, pudb และ wdb นอกจากนี้ยังมีดีบักเกอร์เฉพาะ IDE บางตัวเช่น pydev engine หรือ PTVSการจัดรูปแบบการบันทึก Python
'%(asctime)s — %(name)s — %(levelname)s — %(funcName)s:%(lineno)d — %(message)s'
2018-02-07 19:47:41,864 - a.b.c - WARNING - :1 - hello world
Python Logging Handler
console_handler = logging.StreamHandler() file_handler = logging.FileHandler('filename')
Python Logger
toto_logger = logging.getLogger('toto')
logging.getLogger('toto')
จะส่งคืนวัตถุเดียวกัน:assert id(logging.getLogger('toto')) == id(logging.getLogger('toto'))
logging.debug()
ถูกนำมาใช้. ตามค่าเริ่มต้นระดับบันทึกรูทคือ WARN ดังนั้นทุกบันทึกที่มีระดับต่ำกว่า (เช่นผ่าน logging.info('info')
) จะถูกละเว้น ความพิเศษอีกประการหนึ่งของ root logger คือตัวจัดการเริ่มต้นจะถูกสร้างขึ้นในครั้งแรกที่บันทึกบันทึกที่มีระดับมากกว่า WARN ใช้ root logger โดยตรงหรือโดยอ้อมผ่านวิธีการเช่น logging.debug()
โดยทั่วไปไม่แนะนำlab = logging.getLogger('a.b') assert lab.parent == logging.root # lab's parent is indeed the root logger
la = logging.getLogger('a') assert lab.parent == la # lab's parent is now la instead of root
toto_logger = logging.getLogger('toto') assert toto_logger.level == logging.NOTSET # new logger has NOTSET level assert toto_logger.getEffectiveLevel() == logging.WARN # and its effective level is the root logger level, i.e. WARN # attach a console handler to toto_logger console_handler = logging.StreamHandler() toto_logger.addHandler(console_handler) toto_logger.debug('debug') # nothing is displayed as the log level DEBUG is smaller than toto effective level toto_logger.setLevel(logging.DEBUG) toto_logger.debug('debug message') # now you should see 'debug message' on screen
แนวทางปฏิบัติที่ดีที่สุดในการบันทึก Python
logging.info()
ซึ่งจะเรียก root logger ที่อยู่เบื้องหลังฉาก หากคุณต้องการตรวจจับข้อความแสดงข้อผิดพลาดจากไลบรารีที่คุณใช้ตรวจสอบให้แน่ใจว่าได้กำหนดค่าตัวบันทึกรูทเพื่อเขียนลงไฟล์เช่นเพื่อให้การดีบักง่ายขึ้น โดยค่าเริ่มต้นผู้บันทึกรากจะแสดงผลเป็น stderr
เท่านั้นดังนั้นบันทึกจึงสูญหายได้ง่ายlogging.getLogger(logger name)
ฉันมักจะใช้ __name__
เป็นชื่อคนตัดไม้ แต่สามารถใช้อะไรก็ได้ตราบเท่าที่มันสอดคล้องกัน ในการเพิ่มตัวจัดการเพิ่มเติมฉันมักจะมีวิธีที่ส่งคืนคนตัดไม้ (คุณสามารถค้นหาส่วนสำคัญได้ที่ https://gist.github.com/nguyenkims/e92df0f8bd49973f0c94bddf36ed7fd0)import logging import sys from logging.handlers import TimedRotatingFileHandler FORMATTER = logging.Formatter('%(asctime)s — %(name)s — %(levelname)s — %(message)s') LOG_FILE = 'my_app.log' def get_console_handler(): console_handler = logging.StreamHandler(sys.stdout) console_handler.setFormatter(FORMATTER) return console_handler def get_file_handler(): file_handler = TimedRotatingFileHandler(LOG_FILE, when='midnight') file_handler.setFormatter(FORMATTER) return file_handler def get_logger(logger_name): logger = logging.getLogger(logger_name) logger.setLevel(logging.DEBUG) # better to have too much log than not enough logger.addHandler(get_console_handler()) logger.addHandler(get_file_handler()) # with this pattern, it's rarely necessary to propagate the error up to parent logger.propagate = False return logger
my_logger = get_logger('my module name') my_logger.debug('a debug message')
ทำความเข้าใจพื้นฐาน
เครื่องมือดีบั๊กคืออะไร?
บันทึกการแก้ไขข้อบกพร่องคืออะไร?
'การบันทึก' ใน Python คืออะไร?
Python debugger คืออะไร?