2013-04-08 30 views
15

công tácPython: tùy chỉnh khai thác gỗ trên tất cả các module

Tôi có một bộ sưu tập các kịch bản và tôi muốn họ để tạo ra các thông điệp logging thống nhất với thay đổi tối thiểu để module làm đăng những thông điệp thực tế.

Tôi đã viết một mô-đun nhỏ 'custom_logger' mà tôi dự định gọi từ ứng dụng chính một lần, để nó trả về trình ghi nhật ký, sau đó tôi sẽ tiếp tục sử dụng.

Các môđun con tôi được nhập khẩu vào ứng dụng nên chỉ (hay đúng hơn là tôi muốn họ)

  • nên chỉ "nhập khẩu đăng nhập như log" - vì vậy không có gì cụ thể để trang web của tôi được yêu cầu phải thực hiện chúng chỉ chạy nếu ai đó thấy chúng hữu ích.
  • chỉ cần đăng nhập thư bằng log.info/error('message ') mà không cần thêm bất kỳ trang web cụ thể nào cho chúng
  • nên sử dụng trình ghi' gốc 'đã định cấu hình với tất cả định dạng và trình xử lý của nó và không ảnh hưởng đến trình ghi nhật ký gốc cấu hình

* custom_logger.py *

import logging 
import logging.handlers 
import os 
import sys 


def getLogger(name='root', loglevel='INFO'): 
    logger = logging.getLogger(name) 

    # if logger 'name' already exists, return it to avoid logging duplicate 
    # messages by attaching multiple handlers of the same type 
    if logger.handlers: 
    return logger 
    # if logger 'name' does not already exist, create it and attach handlers 
    else: 
    # set logLevel to loglevel or to INFO if requested level is incorrect 
    loglevel = getattr(logging, loglevel.upper(), logging.INFO) 
    logger.setLevel(loglevel) 
    fmt = '%(asctime)s %(filename)-18s %(levelname)-8s: %(message)s' 
    fmt_date = '%Y-%m-%dT%T%Z' 
    formatter = logging.Formatter(fmt, fmt_date) 
    handler = logging.StreamHandler() 
    handler.setFormatter(formatter) 
    logger.addHandler(handler) 

    if logger.name == 'root': 
     logger.warning('Running: %s %s', 
        os.path.basename(sys.argv[0]), 
        ' '.join(sys.argv[1:])) 
    return logger 

Rồi đến các submodule trong đó có một vài thông điệp thử nghiệm với các ví dụ về những gì làm việc và những gì không.

submodule.py

import sys 
import custom_logger 
import logging 


class SubClass(object): 

    def __init__(self): 
    # NOK (no idea why since by default (no name parameter), it should return the root logger) 
    #log = logging.getLogger() 
    #log.info('message from SubClass/__init__') 

    # OK (works as expected) 
    #log = logging.getLogger('root') 
    #log.info('message from SubClass/__init__') 

    # OK (works as expected) 
    log = custom_logger.getLogger('root') 
    log.info('message from SubClass/__init__') 


    def SomeMethod(self): 
    # OK but I'd have to define `log` for every method, which is unacceptable 
    # Please see question below all code snippets 
    log = custom_logger.getLogger('root') 
    log.info('message from SubClass/SomeMethod') 

Và ứng dụng chính: app.py Không có gì đặc biệt ở đây:

#!/usr/bin/python 

import custom_logger 
import submodule 

log = custom_logger.getLogger('root', loglevel='DEBUG') 

log.debug('debug message') 
log.info('info message') 
log.warning('warning message') 
log.error('error message') 

a = submodule.SubClass() # this should produce a log message 
a.SomeMethod()   # so should this 

Output rằng tôi sau và rằng tôi nhận được, chỉ trong một cách cực kỳ xấu xí:

% ./app.py 
2013-04-08T03:07:46BST custom_logger.py WARNING : Running: app.py 
2013-04-08T03:07:46BST app.py    DEBUG : debug message 
2013-04-08T03:07:46BST app.py    INFO : info message 
2013-04-08T03:07:46BST app.py    WARNING : warning message 
2013-04-08T03:07:46BST app.py    ERROR : error message 
2013-04-08T03:07:46BST submodule.py  INFO : message from SubClass/__init__ 
2013-04-08T03:07:46BST submodule.py  INFO : message from SubClass/SomeMethod 

Tôi muốn có thể xác định một trình ghi nhật ký trong app.py và sau đó trong các mô-đun con chỉ sử dụng thư viện ghi nhật ký chuẩn của Python để sử dụng trình ghi nhật ký đã được cấu hình trong app.py.

Ngoài ra, một workaround xấu xí: nếu tôi đặt mã dưới đây sau khi hàng nhập khẩu trong submodule.py:

log = custom_logger.getLogger('root') 

nó sẽ được thực hiện trước khi logger của tôi được cấu hình trong app.py, làm cho hiệu quả submodule, không phải ứng dụng của tôi định cấu hình ghi nhật ký.

Một workaround tôi coi: trong constuctor của lớp lớp con, tôi có thể xác định

self.log = custom_logger.getLogger('root')

và sau đó sử dụng self.log.error ('một số lỗi'). Phải có một cách đẹp hơn - nếu bạn có thể gợi ý điều gì đó hữu ích hoặc chỉ ra nơi tôi hiểu lầm tài liệu, tôi sẽ rất biết ơn!

PS. Tôi đã dành khá nhiều thời gian để đọc bản ghi nhật ký Python (cơ bản và nâng cao) và sách dạy nấu ăn vì vậy nếu tôi đã bỏ lỡ một cái gì đó hữu ích ở đó, hãy chỉ ra nó.

Cảm ơn bạn!

Trả lời

3

Nếu bạn muốn thay đổi trình ghi nhật ký gốc, bạn chỉ có thể sử dụng getLogger() ở mọi nơi, không có đối số.

Về thiết lập cá thể chỉ trong mô-đun chính, bạn có thể khởi tạo trình ghi nhật ký, thêm Trình xử lý của riêng bạn và sử dụng nó trong tất cả các mô-đun con khác (như tôi đã làm dưới đây).

Tôi tạo ra một lớp kế thừa các StreamHandler trong custom_logger.py:

class MyHandler(logging.StreamHandler): 

    def __init__(self): 
     logging.StreamHandler.__init__(self) 
     fmt = '%(asctime)s %(filename)-18s %(levelname)-8s: %(message)s' 
     fmt_date = '%Y-%m-%dT%T%Z' 
     formatter = logging.Formatter(fmt, fmt_date) 
     self.setFormatter(formatter) 

Sau đó, trong submodule.py, tôi đặt getLogger sau khi nhập khẩu và nhận xét nó trong các phương pháp:

import sys 
import logging 

log = logging.getLogger('root') 

class SubClass(object): 

    def __init__(self): 
     log.info('message from SubClass/__init__') 

    def SomeMethod(self): 
     log.info('message from SubClass/SomeMethod') 

Sau đó, trong app.py tôi đã tạo một cá thể Logger (sẽ giống nhau trong tất cả các mô-đun) và thêm trình xử lý của tôi, định dạng đầu ra:

#!/usr/bin/python 

import logging 
import custom_logger 
import submodule 

log = logging.getLogger('root') 
log.setLevel('DEBUG') 
log.addHandler(custom_logger.MyHandler()) 

log.debug('debug message') 
log.info('info message') 
log.warning('warning message') 
log.error('error message') 

a = submodule.SubClass() # this should produce a log message 
a.SomeMethod()   # so should this 

Đầu ra:

./app.py 
2013-04-08T15:20:05EEST app.py    DEBUG : debug message 
2013-04-08T15:20:05EEST app.py    INFO : info message 
2013-04-08T15:20:05EEST app.py    WARNING : warning message 
2013-04-08T15:20:05EEST app.py    ERROR : error message 
2013-04-08T15:20:05EEST submodule.py  INFO : message from SubClass/__init__ 
2013-04-08T15:20:05EEST submodule.py  INFO : message from SubClass/SomeMethod 
+0

Cảm ơn bạn Mihai. Tôi nghĩ rằng tôi sẽ có nhiều thời gian hơn để nhìn vào nó nhưng tôi sẽ cần phải chờ đợi cho ngày cuối tuần. Cho đến nay tôi đã có thể làm cho lớp của tôi làm tất cả (gắn các trình định dạng, xử lý và thiết lập loglevel) hoạt động bằng cách xác định nhật ký như một đối tượng getLogger trong submodule.py. Tôi đã hy vọng điều này có thể được thực hiện mà không đưa những thứ bên ngoài định nghĩa lớp. Câu hỏi của tôi là nhiều hơn "tại sao một số phương pháp tôi đã thực hiện không hoạt động như mong đợi vì tôi muốn hiểu lý do đằng sau nó, trái ngược với việc nhận mã giao cho tôi, nhưng tôi đánh giá cao sự trợ giúp của bạn: –

+0

Tôi đã cập nhật câu trả lời của mình, sau đó bạn có thể xem mã của mô-đun. Bạn có thể thấy trình ghi nhật ký gốc được khởi tạo trong quá trình nhập. Tôi cũng không hiểu tại sao getLogger ("root") không hoạt động giống nhau trong mọi tình huống (bạn có thể làm getLogger() trong app.py và getLogger ("root") trong submodule.py và bạn nhận được những gì bạn cần, nhưng không phải ngược lại) – Mihai

+0

Cách làm cho nó hoạt động với chuyển hướng stdout thành tệp Ví dụ: python ./app.py >> file.log? –

Các vấn đề liên quan