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!
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: –
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
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? –