socialgekon.com
  • หลัก
  • การแก้ไข
  • นวัตกรรม
  • การออกแบบ Ux
  • การแก้ไขปัญหา
ส่วนหลัง

Python Logging: บทช่วยสอนเชิงลึก

เมื่อแอปพลิเคชันมีความซับซ้อนมากขึ้นการมี ดี บันทึกจะมีประโยชน์มากไม่เพียง แต่เมื่อทำการดีบั๊กเท่านั้น แต่ยังให้ข้อมูลเชิงลึกสำหรับปัญหา / ประสิทธิภาพของแอปพลิเคชันด้วย

ไลบรารีมาตรฐาน Python มาพร้อมกับไฟล์ การบันทึก โมดูลที่มีคุณสมบัติการบันทึกพื้นฐานส่วนใหญ่ ด้วยการตั้งค่าอย่างถูกต้องข้อความบันทึกสามารถให้ข้อมูลที่เป็นประโยชน์มากมายเกี่ยวกับเวลาและสถานที่ที่บันทึกถูกเริ่มทำงานตลอดจนบริบทของบันทึกเช่นกระบวนการ / เธรดที่กำลังทำงานอยู่

แม้จะมีข้อดี แต่โมดูลการบันทึกมักถูกมองข้ามเนื่องจากต้องใช้เวลาพอสมควรในการตั้งค่าอย่างถูกต้องและแม้ว่าจะเสร็จสมบูรณ์แล้วก็ตามในความคิดของฉันเอกสารการบันทึกอย่างเป็นทางการที่ https://docs.python.org/3/library/logging.html ไม่ได้ให้แนวทางปฏิบัติที่ดีที่สุดในการบันทึกหรือเน้นความประหลาดใจในการบันทึก



บทแนะนำการบันทึก Python นี้ไม่ได้หมายถึงเอกสารที่สมบูรณ์ในโมดูลการบันทึก แต่เป็นคำแนะนำในการ 'เริ่มต้นใช้งาน' ที่แนะนำแนวคิดการบันทึกบางอย่างรวมถึง 'gotcha' ที่ต้องระวัง โพสต์จะจบลงด้วยแนวทางปฏิบัติที่ดีที่สุดและมีคำแนะนำสำหรับหัวข้อการบันทึกขั้นสูงเพิ่มเติม

โปรดทราบว่าข้อมูลโค้ดทั้งหมดในโพสต์สมมติว่าคุณได้นำเข้าโมดูลการบันทึกแล้ว:

import logging

แนวคิดสำหรับ Python Logging

ส่วนนี้จะให้ภาพรวมเกี่ยวกับแนวคิดบางอย่างที่มักพบในโมดูลการบันทึก

ระดับการบันทึก Python

ระดับบันทึกสอดคล้องกับ 'ความสำคัญ' ที่บันทึก: บันทึก 'ข้อผิดพลาด' ควรเป็นข้อมูลเร่งด่วนมากกว่าบันทึก 'เตือน' ในขณะที่บันทึก 'แก้ไขข้อบกพร่อง' ควรมีประโยชน์เฉพาะเมื่อทำการดีบักแอปพลิเคชัน

มีหกระดับการบันทึกใน Python; แต่ละระดับเชื่อมโยงกับจำนวนเต็มที่ระบุความรุนแรงของบันทึก: NOTSET = 0, DEBUG = 10, INFO = 20, WARN = 30, ERROR = 40 และ CRITICAL = 50

การบันทึก Python

ทุกระดับค่อนข้างตรงไปตรงมา (DEBUG

การจัดรูปแบบการบันทึก Python

โดยทั่วไปแล้วตัวจัดรูปแบบบันทึกจะเสริมสร้างข้อความบันทึกโดยการเพิ่มข้อมูลบริบทเข้าไป การทราบว่ามีการส่งบันทึกเมื่อใดที่ (ไฟล์ 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

Python Logging Handler

ตัวจัดการบันทึกเป็นส่วนประกอบที่เขียน / แสดงบันทึกได้อย่างมีประสิทธิภาพ: แสดงในคอนโซล (ผ่าน StreamHandler) ในไฟล์ (ผ่าน FileHandler) หรือแม้กระทั่งการส่งอีเมลถึงคุณผ่าน SMTPHandler เป็นต้น

ตัวจัดการบันทึกแต่ละรายการมี 2 ฟิลด์ที่สำคัญ:

  • ฟอร์แมตเตอร์ที่เพิ่มข้อมูลบริบทลงในบันทึก
  • ระดับบันทึกที่กรองบันทึกที่มีระดับต่ำกว่า ดังนั้นตัวจัดการบันทึกที่มีระดับ INFO จะไม่จัดการบันทึกการแก้ปัญหา

ตัวจัดการการบันทึก Python

ไลบรารีมาตรฐานมีตัวจัดการจำนวนหนึ่งที่ควรเพียงพอสำหรับกรณีการใช้งานทั่วไป: https://docs.python.org/3/library/logging.handlers.html#module-logging.handlers . สิ่งที่พบบ่อยที่สุดคือ StreamHandler และ FileHandler:

console_handler = logging.StreamHandler() file_handler = logging.FileHandler('filename')

Python Logger

Logger น่าจะเป็นคนที่ถูกใช้โดยตรงบ่อยที่สุดในโค้ดและเป็นรหัสที่ซับซ้อนที่สุด สามารถรับคนตัดไม้ใหม่ได้โดย:

toto_logger = logging.getLogger('toto')

คนตัดไม้มีสามช่องหลัก:

  • การเผยแพร่: ตัดสินใจว่าควรเผยแพร่บันทึกไปยังผู้ปกครองของคนตัดไม้หรือไม่ ตามค่าเริ่มต้นค่าของมันคือ True
  • ระดับ: เช่นเดียวกับระดับตัวจัดการบันทึกระดับคนตัดไม้จะใช้เพื่อกรองบันทึกที่ 'สำคัญน้อยกว่า' ออกไป ยกเว้นไม่เหมือนกับตัวจัดการบันทึกคือระดับจะถูกตรวจสอบที่ 'เด็ก' คนตัดไม้เท่านั้น เมื่อบันทึกถูกเผยแพร่ไปยังผู้ปกครองแล้วระดับจะไม่ถูกตรวจสอบ นี่เป็นพฤติกรรมที่ไม่เข้าใจง่าย
  • Handlers: รายชื่อตัวจัดการที่บันทึกจะถูกส่งไปเมื่อมาถึงคนตัดไม้ สิ่งนี้ช่วยให้การจัดการบันทึกมีความยืดหยุ่นตัวอย่างเช่นคุณสามารถมีตัวจัดการบันทึกไฟล์ที่บันทึกบันทึก DEBUG ทั้งหมดและตัวจัดการบันทึกอีเมลที่จะใช้สำหรับบันทึก CRITICAL เท่านั้น ในเรื่องนี้ความสัมพันธ์ของตัวจัดการคนตัดไม้จะคล้ายกับผู้เผยแพร่ - ผู้บริโภค: บันทึกจะออกอากาศไปยังตัวจัดการทั้งหมดเมื่อผ่านการตรวจสอบระดับคนตัดไม้

การบันทึก Python

คนตัดไม้คือ ไม่เหมือนใคร ตามชื่อหมายความว่าหากมีการสร้างคนตัดไม้ที่มีชื่อว่า 'toto' การเรียกที่ตามมาของ logging.getLogger('toto') จะส่งคืนวัตถุเดียวกัน:

assert id(logging.getLogger('toto')) == id(logging.getLogger('toto'))

อย่างที่คุณอาจเดาได้ว่าคนตัดไม้มีลำดับชั้น ด้านบนของลำดับชั้นคือ root logger ซึ่งสามารถเข้าถึงได้ผ่าน logging.root คนตัดไม้นี้ถูกเรียกเมื่อเมธอดเช่น logging.debug() ถูกนำมาใช้. ตามค่าเริ่มต้นระดับบันทึกรูทคือ WARN ดังนั้นทุกบันทึกที่มีระดับต่ำกว่า (เช่นผ่าน logging.info('info')) จะถูกละเว้น ความพิเศษอีกประการหนึ่งของ root logger คือตัวจัดการเริ่มต้นจะถูกสร้างขึ้นในครั้งแรกที่บันทึกบันทึกที่มีระดับมากกว่า WARN ใช้ root logger โดยตรงหรือโดยอ้อมผ่านวิธีการเช่น logging.debug() โดยทั่วไปไม่แนะนำ

ตามค่าเริ่มต้นเมื่อสร้างคนตัดไม้ใหม่แม่ของมันจะถูกตั้งค่าเป็น root logger:

lab = logging.getLogger('a.b') assert lab.parent == logging.root # lab's parent is indeed the root logger

อย่างไรก็ตามคนตัดไม้ใช้“ สัญลักษณ์จุด” ซึ่งหมายความว่าคนตัดไม้ที่มีชื่อ“ a.b” จะเป็นลูกของคนตัดไม้“ ก.” อย่างไรก็ตามนี่จะเป็นจริงก็ต่อเมื่อมีการสร้างคนตัดไม้“ a” มิฉะนั้นพาเรนต์“ ab” ยังคงเป็นรูท

la = logging.getLogger('a') assert lab.parent == la # lab's parent is now la instead of root

เมื่อคนตัดไม้ตัดสินใจว่าควรส่งบันทึกตามการตรวจสอบระดับหรือไม่ (เช่นหากระดับการบันทึกต่ำกว่าระดับคนตัดไม้บันทึกจะถูกละเว้น) จะใช้ 'ระดับประสิทธิภาพ' แทนระดับจริง ระดับที่มีประสิทธิภาพจะเหมือนกับระดับคนตัดไม้หากระดับนั้นไม่ใช่ NOTSET นั่นคือค่าทั้งหมดตั้งแต่ดีบักจนถึงระดับคริติคอล อย่างไรก็ตามหากระดับคนตัดไม้ไม่ได้ตั้งค่าระดับที่มีประสิทธิภาพจะเป็นระดับบรรพบุรุษแรกที่มีระดับที่ไม่ใช่ NOTSET

โดยค่าเริ่มต้นคนตัดไม้ใหม่จะมีระดับ NOTSET และเนื่องจากคนตัดไม้รูทมีระดับ WARN ระดับประสิทธิภาพของคนตัดไม้จะเป็น WARN ดังนั้นแม้ว่าคนตัดไม้ใหม่จะมีตัวจัดการบางตัวติดอยู่ตัวจัดการเหล่านี้จะไม่ถูกเรียกเว้นแต่ระดับการบันทึกจะเกิน WARN:

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

โมดูลการบันทึกนั้นมีประโยชน์มาก แต่ก็มีนิสัยแปลก ๆ บางอย่างที่อาจทำให้ปวดหัวเป็นเวลานานได้ Python นักพัฒนา นี่คือแนวทางปฏิบัติที่ดีที่สุดสำหรับการใช้โมดูลนี้ในความคิดของฉัน:

  • กำหนดค่า root logger แต่ห้ามใช้ในโค้ดของคุณเช่นห้ามเรียกใช้ฟังก์ชันเช่น 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')
  • ใช้คลาส RotatingFileHandler เช่น TimedRotatingFileHandler ที่ใช้ในตัวอย่างแทน FileHandler เนื่องจากจะหมุนไฟล์ให้คุณโดยอัตโนมัติเมื่อไฟล์มีขนาดถึงขีด จำกัด หรือทำเป็นประจำทุกวัน
  • ใช้เครื่องมือเช่น Sentry, Airbrake, Raygun และอื่น ๆ เพื่อจับบันทึกข้อผิดพลาดโดยอัตโนมัติสำหรับคุณ สิ่งนี้มีประโยชน์อย่างยิ่งในบริบทของเว็บแอปซึ่งบันทึกอาจมีรายละเอียดมากและบันทึกข้อผิดพลาดอาจสูญหายได้ง่าย ข้อดีอีกประการหนึ่งของการใช้เครื่องมือเหล่านี้คือคุณสามารถรับรายละเอียดเกี่ยวกับค่าตัวแปรในข้อผิดพลาดเพื่อให้คุณสามารถทราบว่า URL ใดทำให้เกิดข้อผิดพลาดผู้ใช้รายใดมีความกังวล ฯลฯ

หากคุณสนใจแนวทางปฏิบัติที่ดีที่สุดเพิ่มเติมโปรดอ่าน 10 ข้อผิดพลาดที่พบบ่อยที่สุดที่นักพัฒนา Python ทำ โดยเพื่อน ApeeScapeer Martin Chikilian

ทำความเข้าใจพื้นฐาน

เครื่องมือดีบั๊กคืออะไร?

เครื่องมือดีบักคือเครื่องมือที่ช่วยให้นักพัฒนาสามารถตรวจจับข้อผิดพลาดและตรวจสอบปัญหาได้ อาจเป็นเครื่องมือบรรทัดคำสั่งเช่น gdb, pdb (สำหรับ Python) หรือสามารถฝังใน IDE (Visual Studio, ชุดความคิด ฯลฯ )

บันทึกการแก้ไขข้อบกพร่องคืออะไร?

นี่เป็นเพียงผลลัพธ์ของโปรแกรมซึ่งเป็น 'การพิมพ์' เวอร์ชันที่ดีกว่าในแง่ของคนธรรมดา ในบริบทของเว็บแอปพลิเคชันบันทึกนี้มักจะมีข้อมูลการร้องขอที่เข้ามาเช่นเส้นทางการร้องขอเวลาขอสถานะ HTTP เป็นต้น

'การบันทึก' ใน Python คืออะไร?

การบันทึกเป็นโมดูลในไลบรารีมาตรฐาน Python ที่จัดเตรียมบันทึกที่มีรูปแบบสมบูรณ์พร้อมตัวกรองที่ยืดหยุ่นและความเป็นไปได้ในการเปลี่ยนเส้นทางบันทึกไปยังแหล่งอื่นเช่น syslog หรืออีเมล

Python debugger คืออะไร?

python debugger ที่นิยมมากที่สุดคือ pdb ขณะนี้มีบางโครงการที่ทำงานเพื่อปรับปรุงการใช้งานของ pdb โดยการจัดเตรียมการเติมแท็บไวยากรณ์สีการเรียกดูโค้ดหรือการดีบักระยะไกล โครงการเหล่านี้ ได้แก่ ipdb, pudb และ wdb นอกจากนี้ยังมีดีบักเกอร์เฉพาะ IDE บางตัวเช่น pydev engine หรือ PTVS

วิธีเปลี่ยนชื่อ Instagram ของคุณและเป็นการฝึกฝนที่ไม่ดีหรือไม่?

กำลังโพสต์

วิธีเปลี่ยนชื่อ Instagram ของคุณและเป็นการฝึกฝนที่ไม่ดีหรือไม่?
เร่งการพัฒนาแอปพลิเคชันด้วย Bootstrap

เร่งการพัฒนาแอปพลิเคชันด้วย Bootstrap

ส่วนหน้าของเว็บ

โพสต์ยอดนิยม
วิธียกเลิกการสมัครรับข้อมูลบน iPhone
วิธียกเลิกการสมัครรับข้อมูลบน iPhone
ขีด จำกัด พื้นที่เก็บข้อมูล Google Photos: พื้นที่เก็บข้อมูลฟรีไม่จำกัดจริงหรือ
ขีด จำกัด พื้นที่เก็บข้อมูล Google Photos: พื้นที่เก็บข้อมูลฟรีไม่จำกัดจริงหรือ
คู่มือเริ่มต้นสำหรับการถ่ายภาพใต้น้ำบน iPhone
คู่มือเริ่มต้นสำหรับการถ่ายภาพใต้น้ำบน iPhone
วิธีลบบุคคลออกจากรูปภาพบน iPhone
วิธีลบบุคคลออกจากรูปภาพบน iPhone
Mini Tutorial - ใช้ประโยชน์จากคุณสมบัติของ Figma สำหรับกระบวนการออกแบบทั้งหมด
Mini Tutorial - ใช้ประโยชน์จากคุณสมบัติของ Figma สำหรับกระบวนการออกแบบทั้งหมด
 
โฮสติ้งสำหรับนักพัฒนาอิสระ: PaaS, VPS, Cloud และอื่น ๆ
โฮสติ้งสำหรับนักพัฒนาอิสระ: PaaS, VPS, Cloud และอื่น ๆ
ข้อผิดพลาดที่เลวร้ายที่สุด 12 ประการที่นักพัฒนา WordPress ขั้นสูงสร้างขึ้น
ข้อผิดพลาดที่เลวร้ายที่สุด 12 ประการที่นักพัฒนา WordPress ขั้นสูงสร้างขึ้น
Ditch MVPs ใช้ต้นแบบขั้นต่ำที่ทำงานได้ (MVPr)
Ditch MVPs ใช้ต้นแบบขั้นต่ำที่ทำงานได้ (MVPr)
เร่งการพัฒนาแอปพลิเคชันด้วย Bootstrap
เร่งการพัฒนาแอปพลิเคชันด้วย Bootstrap
ข้อ จำกัด ในการออกแบบ UX มือถือแนวทางปฏิบัติที่ดีที่สุดและการทำงานร่วมกับนักพัฒนา
ข้อ จำกัด ในการออกแบบ UX มือถือแนวทางปฏิบัติที่ดีที่สุดและการทำงานร่วมกับนักพัฒนา
หมวดหมู่
การเพิ่มขึ้นของระยะไกลวิทยาศาสตร์ข้อมูลและฐานข้อมูลการแก้ไขนักลงทุนและเงินทุนมือถือการจัดการวิศวกรรมการทำกำไรและประสิทธิภาพกำลังโพสต์แนวโน้มผู้คนและทีมงาน

© 2023 | สงวนลิขสิทธิ์

socialgekon.com