Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Python

Python Logging: คู่มือการบันทึกกิจกรรม

คุณเพิ่งสร้างแอปพลิเคชันและสังเกตว่าบางอย่างทำงานไม่ได้ตามที่ตั้งใจ ฟีเจอร์ที่คุณเพิ่งนำไปใช้พฤติกรรมในลักษณะที่คุณไม่คาดหวัง คุณควรทำอย่างไร? คุณจะแก้ไขปัญหานี้อย่างไร?

ในการพัฒนาซอฟต์แวร์ โปรแกรมเมอร์พึ่งพาการ logging (บันทึกกิจกรรม) เพื่อติดตามเหตุการณ์ขณะที่ซอฟต์แวร์ของพวกเขากำลังทำงาน นี่ช่วยให้พวกเขาติดตามแหล่งที่มาของปัญหาได้อย่างมีประสิทธิภาพหากเกิดขึ้น

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

ทำไมคุณควรเก็บ Logs

การเก็บ Logs ช่วยให้คุณเขียนโค้ดที่บำรุงรักษาได้ง่ายขึ้น เมื่อคุณใช้โมดูลอย่าง logging คุณสามารถเก็บบันทึกที่แม่นยำของเหตุการณ์ทั้งหมดที่เกิดขึ้นในโปรแกรมของคุณได้ นี่หมายความว่าคุณสามารถเห็นได้ว่าบรรทัดโค้ดไหนรันแล้ว และบรรทัดไหนล้มเหลวในการดำเนินการ

ใน Python นักพัฒนาบ่อยครั้งพึ่งพาคำสั่ง print() เพื่อ log โค้ดของพวกเขา นี่เป็นแนวปฏิบัติที่ทุกคน - จากผู้เริ่มต้นถึงผู้เชี่ยวชาญ - ต้องต้องรู้สึกผิดที่ใช้ และมีเหตุผลที่ดี คำสั่ง print() ใช้ง่าย มันเรียบง่าย

อย่างไรก็ตาม คำสั่ง print() ไม่ใช่วิธีที่ดีที่สุดในการเก็บ logs ของโค้ดของคุณ สิ่งหนึ่ง คำสั่ง print() สามารถใช้พิมพ์เอาต์พุตใดๆ ไปยังคอนโซลได้ นี่หมายความว่ามันอาจสับสนที่จะแยกแยะว่าการเอาต์พุตไหนควรจัดเก็บเป็น log และการเอาต์พุตไหนเป็นส่วนหนึ่งของโปรแกรมหลักของคุณ เพิ่มเติม คำสั่ง print() ไม่ได้บันทึก logs ของคุณโดยค่าเริ่มต้น

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

วิธีใช้โมดูล Python Logging

ในบทช่วยสอนนี้ เราจะเพิ่มข้อความ logging พื้นฐานลงในโปรแกรมที่วนผ่านลิสต์เกรดนักเรียนและคำนวณว่าพวกเขาสอบผ่านหรือไม่ผ่าน พิจารณาโค้ดต่อไปนี้:

students = ["Martin", "Lewis", "Terri", "Bart"]
grades = [92, 78, 72, 38]
pass_fail = []
for i in range(0, len(students)):
    print("Calculating grade for {}".format(students[i]))
    if grades[i] > 55:
        pass_fail.append(True)
        print("{} has passed their exam.".format(students[i]))
    else:
        pass_fail.append(False)
        print("{} has failed their exam.".format(students[i]))
print("Student grades have been calculated. Moving on to send emails to parents of students who have failed their exams.")

โค้ดด้านบนคำนวณว่านักเรียน 5 คนในชั้นประถมศึกษาปีที่ 4 สอบผ่านหรือไม่ ในโปรแกรมของเรา เราประกาศลิสต์ 3 ลิสต์ ลิสต์หนึ่งเก็บชื่อนักเรียนแต่ละคน อีกลิสต์เก็บเกรดที่นักเรียนแต่ละคนได้ ลิสต์สุดท้ายเก็บว่านักเรียนสอบผ่านหรือไม่ผ่าน

เมื่อเรารันโปรแกรมของเรา จะได้ผลดังนี้:

Calculating grade for Martin.
Martin has passed their exam.
Calculating grade for Lewis.
Lewis has passed their exam.
Calculating grades for Terri.
Terri has passed their exam.
Calculating grades for Bart.
Bart has failed their exam.

คำสั่ง print() แสดงว่าโค้ดของเราทำงาน แต่เราสามารถใช้โมดูล logging() เพื่อแสดงข้อมูลนี้แทนได้ นี่จะช่วยให้เราแยกแยะข้อความ debug จากเอาต์พุตของโปรแกรมของเราได้

เพื่อเริ่มต้น มาเพิ่มไลบรารีมาตรฐาน logging ไว้ที่ด้านบนของโปรแกรมของเรา:

import logging

ตอนนี้ที่เรานำเข้าไลบรารี logging แล้ว เราสามารถเริ่มติดตาม logs ในโค้ดของเราได้ สำหรับตัวอย่างนี้ เราจะติดตาม logs โดยใช้การตั้งค่า DEBUG เนื่องจากเราไม่สนใจติดตามคำเตือนในขณะนี้ สำหรับการอ้างอิง นี่คือตัวเลือก logging ที่คุณสามารถระบุได้:

  • CRITICAL: ใช้แสดงข้อผิดพลาดรุนแรง (logging.critical())
  • ERROR: ใช้แสดงปัญหา (logging.error())
  • WARNING: ใช้แสดงพฤติกรรมที่ไม่คาดคิด (logging.warning())
  • INFO: ใช้แสดงโปรแกรมทำงานอยู่ (logging.info())
  • DEBUG: ใช้ debug โค้ด (logging.debug())

การตั้งค่าเริ่มต้นสำหรับไลบรารี logging คือ WARNING ดังนั้นเราจะต้องตั้งค่าใหม่ด้วยโค้ดนี้:

import logging
logging.basicConfig(level=logging.DEBUG)

ตอนนี้เราพร้อมที่จะเริ่ม debug โค้ดของเรา มาแทนที่คำสั่ง print() ที่บอกเราว่ากำลังคำนวณเกรดหรือว่าโปรแกรมของเราเสร็จแล้ว ด้วยคำสั่ง debug:

import logging
logging.basicConfig(level=logging.DEBUG)
students = ["Martin", "Lewis", "Terri", "Bart"]
grades = [92, 78, 72, 38]
pass_fail = []
for i in range(0, len(students)):
    logging.debug("Calculating grade for {}".format(students[i]))
    if grades[i] > 55:
        pass_fail.append(True)
        print("{} has passed their exam.".format(students[i]))
    else:
        pass_fail.append(False)
        print("{} has failed their exam.".format(students[i]))
logging.debug("Student grades have been calculated. Moving on to send emails to parents of students who have failed their exams.")

เมื่อเรารันโค้ดของเรา จะได้ผลดังนี้:

DEBUG:root:Calculating grade for Martin
Martin has passed their exam.
DEBUG:root:Calculating grade for Lewis
Lewis has passed their exam.
DEBUG:root:Calculating grade for Terri
Terri has passed their exam.
DEBUG:root:Calculating grade for Bart
Bart has failed their exam.
DEBUG:root:Student grades have been calculated. Moving on to send emails to parents of students who have failed their exams.

คุณเห็นได้ว่าการเอาต์พุตของเรามีเนื้อหาเหมือนเดิม อย่างไรก็ตาม ข้อความ "Calculating grade for..." และข้อความแจ้งว่าเกรดคำนวณแล้วปรากฏต่างออกไป ข้อความ "DEBUG:root:" ปรากฏก่อนคำพูดเหล่านั้น

นี่ช่วยให้เราติดตามได้ว่าโปรแกรมของเรากำลังทำอะไรในเวลาใดก็ตาม เนื่องจากโมดูล logging events เพิ่มข้อความดังกล่าวเข้าไปในโปรแกรมของเรา จึงง่ายที่จะ 알아ว่า ข้อความไหนถูกส่งออกโดยโปรแกรมของเรา และข้อความไหนเป็นสำหรับ debugging

ในกรณีนี้ ข้อความ "[student] has failed their exam" เป็นข้อมูลสำคัญที่บอกเราว่าแต่ละนักเรียนสอบผ่านหรือไม่ ข้อมูลอื่นๆ มีประโยชน์ในการดูว่าโปรแกรมของเราทำงานอย่างไร แต่ไม่มีประโยชน์ต่อผู้ใช้ ดังนั้นเราจึงติดตามคำพูดเหล่านี้โดยใช้ logging calls

วิธีเก็บ Logs ในไฟล์

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

สิ่งที่คุณต้องทำคือ รวมอาร์กิวเมนต์ filename ในบรรทัดการกำหนดค่า logging handler ของคุณ และโปรแกรมของคุณจะบันทึก logs ลงในไฟล์โดยอัตโนมัติ:

import logging
logging.basicConfig(level=logging.DEBUG, filename="student_data.log")
...

เมื่อเรารันโค้ดของเรา logs ของเราจะถูกเพิ่มไปยังชื่อไฟล์ที่เราระบุ หากเราเปิดไฟล์ "student_data.log" จะได้ผลดังนี้:

DEBUG:root:Calculating grade for Martin
DEBUG:root:Calculating grade for Lewis
DEBUG:root:Calculating grade for Terri
DEBUG:root:Calculating grade for Bart
DEBUG:root:Student grades have been calculated. Moving on to send emails to parents of students who have failed their exams.

สังเกตว่า debug output ของเรามีเฉพาะข้อความที่เราระบุเป็น logs โดยใช้เมธอด logging.debug() นี่มีประโยชน์เพราะช่วยให้เราแยกแยะ program output - ซึ่งแสดงโดยคำสั่ง print() - จาก debug logs

คุณยังสามารถเพิ่มพารามิเตอร์เพื่อติดตามเวลาที่รายการถูกเพิ่มใน log ของคุณ เราสามารถทำได้ด้วยโค้ดต่อไปนี้:

logging.basicConfig(
    level=logging.DEBUG,
    filename="student_data.log",
    format="%(asctime)s:%(levelname)s:%(message)s"
)

โค้ดนี้เพิ่มข้อมูลต่อไปนี้ลงในไฟล์ student_data.log ของเรา:

2020-06-18 08:27:50,123:DEBUG:Calculating grade for Martin
2020-06-18 08:27:50,123:DEBUG:Calculating grade for Lewis
2020-06-18 08:27:50,123:DEBUG:Calculating grade for Terri
2020-06-18 08:27:50,123:DEBUG:Calculating grade for Bart
2020-06-18 08:27:50,124:DEBUG:Student grades have been calculated. Moving on to send emails to parents of students who have failed their exams.

ตอนนี้เรารู้ว่าแต่ละบรรทัดของโค้ดของเราถูกดำเนินการเมื่อไหร่ ในโปรแกรมที่ยาวกว่า ข้อมูลนี้จะมีประโยชน์เป็นพิเศษ เพราะจะช่วยให้เราเข้าใจลำดับที่โค้ดของเรารันและความเร็วของโค้ดของเรา

สรุป

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