การใช้การบันทึกในหลายโมดูล


257

ฉันมีโครงการงูหลามขนาดเล็กที่มีโครงสร้างดังต่อไปนี้ -

Project 
 -- pkg01
   -- test01.py
 -- pkg02
   -- test02.py
 -- logging.conf

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

import logging.config

logging.config.fileConfig('logging.conf')
logger = logging.getLogger('pyApp')

logger.info('testing')

ในปัจจุบันฉันทำการเริ่มต้นนี้ในทุกโมดูลก่อนที่ฉันจะเริ่มบันทึกข้อความ เป็นไปได้หรือไม่ที่จะทำการเริ่มต้นนี้เพียงครั้งเดียวในที่เดียวซึ่งการตั้งค่าเดียวกันนี้สามารถนำกลับมาใช้ใหม่ได้โดยการบันทึกทั่วทั้งโครงการ?


3
ในการตอบกลับความคิดเห็นของคุณเกี่ยวกับคำตอบของฉัน: คุณไม่จำเป็นต้องโทรหาfileConfigในทุกโมดูลที่เข้าสู่ระบบเว้นแต่คุณจะมีif __name__ == '__main__'เหตุผลในทุกข้อ คำตอบที่หญิงไม่ได้เป็นวิธีปฏิบัติที่ดีถ้าแพคเกจเป็นห้องสมุดแม้ว่ามันอาจจะทำงานให้คุณ - หนึ่งไม่ควรเข้าสู่ระบบการกำหนดค่าในแพคเกจห้องสมุดอื่น ๆ NullHandlerกว่าจะเพิ่ม
Vinay Sajip

1
prost บอกเป็นนัยว่าเราจำเป็นต้องเรียกใช้ stmts นำเข้าและคนตัดไม้ในทุกโมดูลและเรียกเฉพาะ fileconfig stmt ในโมดูลหลัก ไม่คล้ายกับสิ่งที่คุณกำลังพูด?
Quest Monger

6
package/__init__.pyหญิงบอกว่าคุณควรใส่รหัสการเข้าสู่ระบบการตั้งค่าใน ปกติแล้วสถานที่ที่คุณใส่if __name__ == '__main__'รหัสจะไม่ใช่สถานที่ นอกจากนี้ตัวอย่างของ prost ดูเหมือนว่าจะเรียกรหัสการกำหนดค่าโดยไม่มีเงื่อนไขเมื่อนำเข้าซึ่งไม่ได้ดูเหมาะสมกับฉัน โดยทั่วไปแล้วรหัสการกำหนดค่าการบันทึกควรทำในที่เดียวและไม่ควรเกิดผลข้างเคียงของการนำเข้ายกเว้นเมื่อคุณกำลังนำเข้า __main__
Vinay Sajip

คุณพูดถูกฉันพลาดเส้น '# package / __ init__.py' ในตัวอย่างโค้ดของเขา ขอบคุณสำหรับจุดที่ออกและความอดทนของคุณ
Quest Monger

1
ดังนั้นสิ่งที่เกิดขึ้นถ้าคุณมีหลายif __name__ == '__main__'? (ไม่ได้กล่าวถึงอย่างชัดเจนในคำถามหากเป็นกรณีนี้)
kon Psych

คำตอบ:


293

แนวทางปฏิบัติที่ดีที่สุดคือในแต่ละโมดูลจะมีตัวบันทึกไว้ดังนี้:

import logging
logger = logging.getLogger(__name__)

ใกล้กับส่วนบนของโมดูลและจากนั้นในรหัสอื่น ๆ ในโมดูลทำเช่น

logger.debug('My message with %s', 'variable data')

หากคุณต้องการแบ่งกิจกรรมการบันทึกภายในโมดูลให้ใช้เช่น

loggerA = logging.getLogger(__name__ + '.A')
loggerB = logging.getLogger(__name__ + '.B')

และเข้าสู่ระบบloggerAและloggerBตามความเหมาะสม

ในโปรแกรมหลักหรือโปรแกรมของคุณให้ทำเช่น:

def main():
    "your program code"

if __name__ == '__main__':
    import logging.config
    logging.config.fileConfig('/path/to/logging.conf')
    main()

หรือ

def main():
    import logging.config
    logging.config.fileConfig('/path/to/logging.conf')
    # your program code

if __name__ == '__main__':
    main()

ดูที่นี่สำหรับการบันทึกจากหลายโมดูลและที่นี่สำหรับการกำหนดค่าการบันทึกสำหรับรหัสซึ่งจะใช้เป็นโมดูลไลบรารีด้วยรหัสอื่น

อัปเดต:เมื่อโทรfileConfig()คุณอาจต้องการระบุdisable_existing_loggers=Falseว่าคุณใช้ Python 2.6 หรือใหม่กว่า (ดูเอกสารสำหรับข้อมูลเพิ่มเติม) ค่าเริ่มต้นTrueสำหรับการเข้ากันได้แบบย้อนกลับซึ่งทำให้ตัวบันทึกที่มีอยู่ทั้งหมดจะถูกปิดใช้งานโดยfileConfig()ถ้าพวกเขาหรือบรรพบุรุษของพวกเขามีการตั้งชื่ออย่างชัดเจนในการกำหนดค่า ด้วยการตั้งค่าเป็นตัวFalseบันทึกที่มีอยู่จะถูกทิ้งไว้ตามลำพัง หากใช้ Python 2.7 / Python 3.2 หรือใหม่กว่าคุณอาจต้องการพิจารณาdictConfig()API ที่ดีกว่าfileConfig()เนื่องจากให้การควบคุมมากกว่าการกำหนดค่า


21
ถ้าคุณดูตัวอย่างของฉันฉันกำลังทำสิ่งที่คุณแนะนำข้างต้นแล้ว คำถามของฉันคือฉันจะรวมศูนย์การเริ่มต้นการบันทึกนี้ได้อย่างไรซึ่งฉันไม่จำเป็นต้องทำซ้ำคำสั่งทั้งสาม ในตัวอย่างของคุณคุณพลาด stmt 'logging.config.fileConfig (' logging.conf ')' stmt นี้จริง ๆ แล้วเป็นสาเหตุของความกังวลของฉัน คุณจะเห็นว่าถ้าฉันเริ่มต้นคนตัดไม้ในทุกโมดูลฉันจะต้องพิมพ์ stmt นี้ในทุกโมดูล นั่นหมายถึงการติดตามเส้นทางของไฟล์ conf ในทุกโมดูลซึ่งดูไม่เป็นแนวปฏิบัติที่ดีที่สุดสำหรับฉัน (ลองนึกภาพความเสียหายเมื่อเปลี่ยนตำแหน่งโมดูล / แพ็กเกจ)
Quest Monger

4
หากคุณเรียกใช้ fileConfig หลังจากสร้างตัวบันทึกไม่ว่าจะอยู่ในโมดูลเดียวกันหรือในโมดูลอื่น (เช่นเมื่อคุณสร้างตัวบันทึกที่ด้านบนของไฟล์) จะไม่ทำงาน การกำหนดค่าการบันทึกใช้กับตัวบันทึกที่สร้างขึ้นหลังจากเท่านั้น ดังนั้นวิธีการนี้ใช้ไม่ได้หรือไม่ใช่ตัวเลือกที่ใช้การได้สำหรับหลายโมดูล @Quest Monger: คุณสามารถสร้างไฟล์อื่นที่เก็บตำแหน่งไฟล์ config .. ;)
Vincent Ketelaars

2
@Oxidator: ไม่จำเป็นต้อง - ดูdisable_existing_loggersธงซึ่งเป็นTrueค่าเริ่มต้น Falseแต่สามารถกำหนดให้
Vinay Sajip

1
@Vayay Sajip ขอบคุณ คุณมีคำแนะนำสำหรับตัวบันทึกที่ทำงานในโมดูล แต่อยู่นอกคลาสด้วยหรือไม่ เนื่องจากการนำเข้าเสร็จสิ้นก่อนที่จะเรียกใช้ฟังก์ชั่นหลักบันทึกเหล่านั้นจะถูกบันทึกไว้แล้ว ฉันเดาว่าการตั้งค่าตัวบันทึกของคุณก่อนที่การนำเข้าทั้งหมดในโมดูลหลักจะเป็นวิธีเดียวหรือไม่ คนตัดไม้นี้สามารถถูกเขียนทับในหลักถ้าคุณชอบ
Vincent Ketelaars

1
หากฉันต้องการให้ตัวบันทึกเฉพาะโมดูลของฉันทั้งหมดมีระดับการบันทึกที่แตกต่างจากคำเตือนเริ่มต้นฉันจะต้องทำการตั้งค่านั้นในแต่ละโมดูลหรือไม่ บอกว่าฉันต้องการให้โมดูลทั้งหมดของฉันเข้าสู่ระบบที่ INFO
ราชา

127

จริงๆแล้วทุกคนตัดไม้เป็นลูกของแพคเกจบันทึกของผู้ปกครอง (เช่นpackage.subpackage.moduleสืบทอดการกำหนดค่าจากpackage.subpackage)ดังนั้นสิ่งที่คุณต้องทำคือเพียงแค่การกำหนดค่า root logger ซึ่งสามารถทำได้โดยlogging.config.fileConfig(config ของคุณเองสำหรับ loggers) หรือlogging.basicConfig(ตั้งค่า root logger) . การตั้งค่าการเข้าสู่ระบบในโมดูลรายการของคุณ ( __main__.pyหรือสิ่งที่คุณต้องการที่จะทำงานเช่นmain_script.py. __init__.pyทำงานได้เช่นกัน)

ใช้ basicConfig:

# package/__main__.py
import logging
import sys

logging.basicConfig(stream=sys.stdout, level=logging.INFO)

ใช้ fileConfig:

# package/__main__.py
import logging
import logging.config

logging.config.fileConfig('logging.conf')

จากนั้นสร้างตัวบันทึกทุกตัวโดยใช้:

# package/submodule.py
# or
# package/subpackage/submodule.py
import logging
log = logging.getLogger(__name__)

log.info("Hello logging!")

สำหรับข้อมูลเพิ่มเติมดูสินค้าทุกประเภทเข้าสู่ระบบการสอน


15
นี่คือวิธีที่ง่ายที่สุดในการแก้ปัญหาโดยไม่ต้องพูดถึงการเปิดเผยและยกระดับความสัมพันธ์ระหว่างผู้ปกครอง - ลูกระหว่างโมดูลสิ่งที่ฉันเป็น noob ก็ไม่รู้ danke
Quest Monger

คุณพูดถูก และเมื่อ vinay ชี้ให้เห็นในโพสต์ของเขาทางออกของคุณถูกต้องตราบใดที่ไม่ใช่ในโมดูลinit .py โซลูชันของคุณใช้งานได้เมื่อฉันใช้กับโมดูลหลัก (จุดเข้า)
Quest Monger

2
จริง ๆ แล้วคำตอบที่เกี่ยวข้องมากขึ้นตั้งแต่คำถามเกี่ยวข้องกับโมดูลแยกต่างหาก
Jan Sila

1
บางทีคำถามโง่: หากไม่มีตัวบันทึก__main__.py(เช่นถ้าฉันต้องการใช้โมดูลในสคริปต์ที่ไม่มีตัวบันทึก) จะlogging.getLogger(__name__)ยังคงทำการบันทึกในโมดูลหรือมันจะยกข้อยกเว้น?
Bill

1
ในที่สุด ฉันมีตัวบันทึกการทำงาน แต่มันล้มเหลวใน Windows สำหรับ Parallel ที่ทำงานด้วย joblib ฉันเดาว่านี่เป็นคู่มือการปรับแต่งระบบ - อย่างอื่นผิดปกติกับ Parallel แต่มันได้ผลแน่นอน! ขอบคุณ
B Furtado

17

ฉันมักจะทำมันดังต่อไปนี้

ใช้ไฟล์หลามเดียวเพื่อกำหนดค่าบันทึกของฉันเป็นรูปแบบซิงเกิลที่มีชื่อว่า ' log_conf.py'

#-*-coding:utf-8-*-

import logging.config

def singleton(cls):
    instances = {}
    def get_instance():
        if cls not in instances:
            instances[cls] = cls()
        return instances[cls]
    return get_instance()

@singleton
class Logger():
    def __init__(self):
        logging.config.fileConfig('logging.conf')
        self.logr = logging.getLogger('root')

ในโมดูลอื่นเพียงนำเข้าการกำหนดค่า

from log_conf import Logger

Logger.logr.info("Hello World")

นี่คือรูปแบบซิงเกิลเพื่อเข้าสู่ระบบได้อย่างง่ายดายและมีประสิทธิภาพ


1
ขอบคุณสำหรับรายละเอียดรูปแบบซิงเกิล ฉันวางแผนที่จะใช้สิ่งนี้ แต่แล้วโซลูชัน @prost นั้นง่ายกว่าและเหมาะสมกับความต้องการของฉันอย่างสมบูรณ์แบบ อย่างไรก็ตามฉันเห็นว่าโซลูชันของคุณมีประโยชน์คือโครงการขนาดใหญ่ที่มีหลายจุดเข้าใช้ (นอกเหนือจากหลัก) danke
Quest Monger

46
นี่มันไร้ประโยชน์ root logger เป็น singleton อยู่แล้ว เพียงใช้ logging.info แทน Logger.logr.info
ฝัก

9

คำตอบเหล่านี้หลายคำแนะนำว่าที่ด้านบนของโมดูลที่คุณทำ

import logging
logger = logging.getLogger(__name__)

มันเป็นความเข้าใจของฉันที่นี้ถือว่าการปฏิบัติที่เลวร้ายมาก เหตุผลคือการกำหนดค่าไฟล์จะปิดการใช้งานบันทึกที่มีอยู่ทั้งหมดโดยค่าเริ่มต้น เช่น

#my_module
import logging

logger = logging.getLogger(__name__)

def foo():
    logger.info('Hi, foo')

class Bar(object):
    def bar(self):
        logger.info('Hi, bar')

และในโมดูลหลักของคุณ:

#main
import logging

# load my module - this now configures the logger
import my_module

# This will now disable the logger in my module by default, [see the docs][1] 
logging.config.fileConfig('logging.ini')

my_module.foo()
bar = my_module.Bar()
bar.bar()

ตอนนี้บันทึกที่ระบุใน logging.ini จะว่างเปล่าเนื่องจากตัวบันทึกที่มีอยู่ถูกปิดใช้งานโดยการเรียกใช้ fileconfig

แม้ว่าจะเป็นไปได้ที่จะหลีกเลี่ยงปัญหานี้ (disable_existing_Loggers = False) ลูกค้าของห้องสมุดของคุณจำนวนมากจะไม่ทราบเกี่ยวกับพฤติกรรมนี้และจะไม่ได้รับบันทึกของคุณ ทำให้ลูกค้าของคุณเป็นเรื่องง่ายด้วยการเรียก logging.getLogger ในพื้นที่เสมอ หมวกเคล็ดลับ: ผมได้เรียนรู้เกี่ยวกับพฤติกรรมนี้จากเว็บไซต์วิคเตอร์ของหลิน

ดังนั้นวิธีปฏิบัติที่ดีคือแทนที่จะเรียกใช้ logging.getLogger แบบโลคัลเสมอ เช่น

#my_module
import logging

logger = logging.getLogger(__name__)

def foo():
    logging.getLogger(__name__).info('Hi, foo')

class Bar(object):
    def bar(self):
        logging.getLogger(__name__).info('Hi, bar')    

นอกจากนี้หากคุณใช้ fileconfig ใน main ให้ตั้งค่า disable_existing_loggers = False ในกรณีที่นักออกแบบไลบรารีของคุณใช้อินสแตนซ์โมดูลตัวบันทึกระดับโมดูล


คุณไม่สามารถวิ่งlogging.config.fileConfig('logging.ini')มาก่อนได้import my_moduleหรือไม่? ตามที่แนะนำในคำตอบนี้
lucid_dreamer

ไม่แน่ใจ - แต่แน่นอนว่ามันจะถือว่าเป็นการปฏิบัติที่ไม่ดีในการผสมผสานการนำเข้าและรหัสที่ปฏิบัติการได้ในลักษณะนั้น คุณไม่ต้องการให้ลูกค้าของคุณต้องตรวจสอบว่าพวกเขาจำเป็นต้องกำหนดค่าการบันทึกก่อนที่พวกเขาจะนำเข้าโดยเฉพาะอย่างยิ่งเมื่อมีทางเลือกเล็กน้อย! ลองนึกภาพถ้าห้องสมุดที่ใช้กันอย่างแพร่หลายเช่นคำขอได้ทำเช่นนั้น .... !
phil_20686

"ไม่แน่ใจ - แต่ก็แน่นอนว่าจะเป็นการปฏิบัติที่ไม่ดีในการผสมผสานการนำเข้าและรหัสที่ปฏิบัติการได้ในลักษณะนั้น" - ทำไม
lucid_dreamer

ฉันยังไม่ชัดเจนว่าทำไมมันถึงไม่ดี และฉันไม่เข้าใจตัวอย่างของคุณอย่างเต็มที่ คุณสามารถโพสต์การกำหนดค่าของคุณสำหรับตัวอย่างนี้และแสดงการใช้งานบางอย่างได้หรือไม่
lucid_dreamer

1
ดูเหมือนว่าคุณจะขัดแย้งกับเอกสารอย่างเป็นทางการ : 'ข้อตกลงที่ดีที่จะใช้เมื่อตั้งชื่อตัวบันทึกคือใช้ตัวบันทึกระดับโมดูลในแต่ละโมดูลที่ใช้การบันทึกชื่อดังนี้: logger = logging.getLogger(__name__)'
iron9

8

วิธีง่ายๆในการใช้อินสแตนซ์หนึ่งของไลบรารีการบันทึกในหลายโมดูลสำหรับฉันคือการติดตามวิธีแก้ไข:

base_logger.py

import logging

logger = logging
logger.basicConfig(format='%(asctime)s - %(message)s', level=logging.INFO)

ไฟล์อื่น ๆ

from base_logger import logger

if __name__ == '__main__':
    logger.info("This is an info message")

7

การขว้างด้วยวิธีอื่น

ใน. โมดูลinitของฉันฉันมีสิ่งต่อไปนี้:

# mymodule/__init__.py
import logging

def get_module_logger(mod_name):
  logger = logging.getLogger(mod_name)
  handler = logging.StreamHandler()
  formatter = logging.Formatter(
        '%(asctime)s %(name)-12s %(levelname)-8s %(message)s')
  handler.setFormatter(formatter)
  logger.addHandler(handler)
  logger.setLevel(logging.DEBUG)
  return logger

จากนั้นในแต่ละโมดูลฉันต้องการคนตัดไม้ฉันทำ:

# mymodule/foo.py
from [modname] import get_module_logger
logger = get_module_logger(__name__)

เมื่อพลาดการบันทึกคุณสามารถแยกความแตกต่างของแหล่งที่มาโดยโมดูลที่มาจาก


"init หลักของโมดูลของฉัน" หมายถึงอะไร และ "จากนั้นในแต่ละชั้นฉันต้องการคนตัดไม้ฉันทำ:"? คุณสามารถให้ตัวอย่างชื่อ _module.py และตัวอย่างการใช้งานเป็นการนำเข้าจากโมดูล caller_module.py ได้หรือไม่ ดูคำตอบนี้สำหรับแรงบันดาลใจของรูปแบบที่ฉันถาม ไม่พยายามที่จะอุปถัมภ์ ฉันพยายามที่จะเข้าใจคำตอบของคุณและฉันรู้ว่าฉันจะถ้าคุณเขียนอย่างนั้น
lucid_dreamer

1
@lucid_dreamer ฉันชี้แจง
Tommy

4

คุณสามารถคิดอะไรทำนองนี้!

def get_logger(name=None):
    default = "__app__"
    formatter = logging.Formatter('%(levelname)s: %(asctime)s %(funcName)s(%(lineno)d) -- %(message)s',
                              datefmt='%Y-%m-%d %H:%M:%S')
    log_map = {"__app__": "app.log", "__basic_log__": "file1.log", "__advance_log__": "file2.log"}
    if name:
        logger = logging.getLogger(name)
    else:
        logger = logging.getLogger(default)
    fh = logging.FileHandler(log_map[name])
    fh.setFormatter(formatter)
    logger.addHandler(fh)
    logger.setLevel(logging.DEBUG)
    return logger

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

a=get_logger("__app___")
b=get_logger("__basic_log__")
a.info("Starting logging!")
b.debug("Debug Mode")

4

@ วิธีแก้ปัญหาของ Yarkee ดูดีขึ้น ฉันต้องการเพิ่มอีกแล้ว -

class Singleton(type):
    _instances = {}

    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances.keys():
            cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
        return cls._instances[cls]


class LoggerManager(object):
    __metaclass__ = Singleton

    _loggers = {}

    def __init__(self, *args, **kwargs):
        pass

    @staticmethod
    def getLogger(name=None):
        if not name:
            logging.basicConfig()
            return logging.getLogger()
        elif name not in LoggerManager._loggers.keys():
            logging.basicConfig()
            LoggerManager._loggers[name] = logging.getLogger(str(name))
        return LoggerManager._loggers[name]    


log=LoggerManager().getLogger("Hello")
log.setLevel(level=logging.DEBUG)

ดังนั้น LoggerManager สามารถเชื่อมต่อกับแอปพลิเคชันทั้งหมดได้ หวังว่ามันจะสมเหตุสมผลและคุ้มค่า


11
โมดูลการบันทึกเกี่ยวข้องกับซิงเกิลตันอยู่แล้ว logging.getLogger ("Hello") จะได้รับตัวบันทึกเดียวกันในโมดูลทั้งหมดของคุณ
Pod

2

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

from flask import Flask
import logging
from logging.handlers import RotatingFileHandler

app = Flask(__name__)

# make default logger output everything to the console
logging.basicConfig(level=logging.DEBUG)

rotating_file_handler = RotatingFileHandler(filename="logs.log")
rotating_file_handler.setLevel(logging.INFO)

app.logger.addHandler(rotating_file_handler)

สร้างไฟล์ util ที่ดีชื่อ logger.py:

import logging

def get_logger(name):
    return logging.getLogger("flask.app." + name)

flask.app เป็นค่าฮาร์ดโค้ดในขวด แอปพลิเคชันตัวบันทึกเริ่มต้นด้วย flask.app เป็นชื่อโมดูลเสมอ

ตอนนี้ในแต่ละโมดูลฉันสามารถใช้งานได้ในโหมดต่อไปนี้:

from logger import get_logger
logger = get_logger(__name__)

logger.info("new log")

สิ่งนี้จะสร้างบันทึกใหม่สำหรับ "app.flask.MODULE_NAME" ด้วยความพยายามขั้นต่ำ


2

แนวทางปฏิบัติที่ดีที่สุดคือการสร้างโมดูลแยกต่างหากซึ่งมีเพียงวิธีเดียวที่มีหน้าที่ที่เราจะต้องให้ตัวจัดการคนตัดไม้กับวิธีการโทร บันทึกไฟล์นี้เป็น m_logger.py

import logger, logging

def getlogger():
    # logger
    logger = logging.getLogger(__name__)
    logger.setLevel(logging.DEBUG)
    # create console handler and set level to debug
    #ch = logging.StreamHandler()
    ch = logging.FileHandler(r'log.txt')
    ch.setLevel(logging.DEBUG)
    # create formatter
    formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
    # add formatter to ch
    ch.setFormatter(formatter)
    # add ch to logger
    logger.addHandler(ch)
    return logger

ตอนนี้เรียกใช้เมธอด getlogger () เมื่อใดก็ตามที่ต้องการตัวจัดการตัวบันทึก

from m_logger import getlogger
logger = getlogger()
logger.info('My mssg')

1
เป็นการดีหากคุณไม่มีพารามิเตอร์เพิ่มเติม แต่ถ้าสมมุติว่าคุณมี--debugตัวเลือกในแอพและต้องการตั้งค่าระดับการบันทึกในตัวบันทึกทั้งหมดในแอปตามพารามิเตอร์นี้ ...
The Godfather

@TheGodfather ใช่มันยากที่จะบรรลุโดยวิธีการนี้ สิ่งที่เราสามารถทำได้ในสถานการณ์นี้คือการสร้างคลาสที่จะใช้ตัวจัดรูปแบบเป็นพารามิเตอร์ในขณะที่การสร้างวัตถุและจะมีฟังก์ชั่นที่คล้ายกันเพื่อส่งกลับตัวจัดการคนตัดไม้มุมมองของคุณในเรื่องนี้คืออะไร?
Mousam Singh

ใช่ฉันทำสิ่งที่คล้ายกันทำget_logger(level=logging.INFO)เพื่อส่งคืนซิงเกิลบางประเภทดังนั้นเมื่อมันเรียกว่าครั้งแรกจากแอพหลักมันเริ่มต้นตัวบันทึกและตัวจัดการด้วยระดับที่เหมาะสมแล้วส่งคืนloggerวัตถุเดียวกันไปยังวิธีอื่นทั้งหมด
เจ้าพ่อ

0

ใหม่สำหรับงูใหญ่ดังนั้นฉันไม่ทราบว่าเป็นสิ่งที่แนะนำหรือไม่

โครงการของคุณต้องมีinit .py ดังนั้นจึงสามารถโหลดเป็นโมดูลได้

# Put this in your module's __init__.py
import logging.config
import sys

# I used this dictionary test, you would put:
# logging.config.fileConfig('logging.conf')
# The "" entry in loggers is the root logger, tutorials always 
# use "root" but I can't get that to work
logging.config.dictConfig({
    "version": 1,
    "formatters": {
        "default": {
            "format": "%(asctime)s %(levelname)s %(name)s %(message)s"
        },
    },
    "handlers": {
        "console": {
            "level": 'DEBUG',
            "class": "logging.StreamHandler",
            "stream": "ext://sys.stdout"
        }
    },
    "loggers": {
        "": {
            "level": "DEBUG",
            "handlers": ["console"]
        }
    }
})

def logger():
    # Get the name from the caller of this function
    return logging.getLogger(sys._getframe(1).f_globals['__name__'])

sys._getframe(1)คำแนะนำมาจากที่นี่

จากนั้นใช้ตัวบันทึกของคุณในไฟล์อื่น:

from [your module name here] import logger

logger().debug("FOOOOOOOOO!!!")

คำเตือน:

  1. คุณต้องเรียกใช้ไฟล์ของคุณเป็นโมดูลมิฉะนั้นimport [your module]จะไม่ทำงาน:
    • python -m [your module name].[your filename without .py]
  2. ชื่อของคนตัดไม้สำหรับจุดเริ่มต้นของโปรแกรมของคุณจะเป็น__main__แต่การแก้ปัญหาใด ๆ ที่ใช้__name__จะมีปัญหานั้น
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.