2012-06-20 65 views
19

Tôi có một tập lệnh Python sử dụng 'Print' để in ra stdout. Gần đây tôi đã thêm ghi nhật ký thông qua Python Logger và muốn làm cho nó để các báo cáo in đi đến logger nếu đăng nhập được kích hoạt. Tôi không muốn sửa đổi hoặc xóa các báo cáo in này.Chuyển hướng đầu ra 'in' của Python sang Logger

Tôi có thể đăng nhập bằng cách thực hiện 'log.info ("một số thông tin msg")'. Tôi muốn có thể làm một việc như sau:

if logging_enabled: 
    sys.stdout=log.info 
print("test") 

Nếu đăng nhập được bật, "kiểm tra" phải được ghi lại như thể tôi đã log.info ("test"). Nếu quá trình ghi nhật ký không được bật, "kiểm tra" chỉ nên được in trên màn hình.

Điều này có khả thi không? Tôi biết tôi có thể chỉ đạo stdout vào một tập tin một cách tương tự (xem: redirect prints to log file)

Trả lời

15

Bạn có hai lựa chọn:

  1. Mở một logfile và thay thế sys.stdout với nó, không phải là một chức năng:

    log = open("myprog.log", "a") 
    sys.stdout = log 
    
    >>> print("Hello") 
    >>> # nothing is printed because it goes to the log file instead. 
    
  2. Replace in với chức năng đăng nhập của bạn:

    # If you're using python 2.x, uncomment the next line 
    #from __future__ import print_function 
    print = log.info 
    
    >>> print("Hello!") 
    >>> # nothing is printed because log.info is called instead of print 
    
+0

Trong ví dụ đầu tiên, là nó có thể có cả hai, trong tập tin và trên stdout màn hình? –

1

Đối với một phương pháp làm việc với 2.x see here:

Trích dẫn

"Kỹ thuật thứ hai đến sự chú ý của tôi khi tôi đọc lại Learning Python cho lần thứ hai. Nó liên quan đến việc chuyển hướng các lệnh in trực tiếp như sau:.

print >>output, "wello horld" 

trong đó sản lượng là một đối tượng có thể ghi"

+2

Trong khi liên kết này có thể trả lời câu hỏi, tốt hơn nên bao gồm các phần thiết yếu của câu trả lời ở đây và cung cấp liên kết để tham khảo. Câu trả lời chỉ liên kết có thể trở thành không hợp lệ nếu trang được liên kết thay đổi. –

+1

@david được ghi chú, thêm đoạn trích – tacaswell

2

Bạn thực sự nên làm điều đó theo cách khác: bằng cách điều chỉnh cấu hình đăng nhập của bạn để sử dụng print tuyên bố hoặc một cái gì đó Không ghi đè hành vi print, vì một số cài đặt có thể được giới thiệu trong tương lai (ví dụ: bạn hoặc người khác sử dụng mô-đun của bạn) có thể thực sự xuất ra stdout và bạn sẽ gặp sự cố .

Có một handl er đó là nghĩa vụ phải chuyển hướng thông điệp tường trình của bạn vào dòng thích hợp (tập tin, stdout hoặc bất cứ điều gì khác như tập tin). Nó được gọi là StreamHandler và được đóng gói với mô-đun logging.

Vì vậy, về cơ bản theo ý kiến ​​của tôi bạn nên làm, những gì bạn đã nói bạn không muốn làm: thay thế các câu print bằng ghi thực tế.

+0

Tôi sẽ sử dụng tính năng ghi nhật ký cho các tập lệnh trong tương lai, nhưng với mục đích của những gì tôi đang làm, không đáng để cập nhật mọi thứ cho trình ghi nhật ký. Tôi sẽ xem xét đến StreamHandler mặc dù. – Rauffle

+0

@Rauffle: Như bạn muốn. Tôi mạnh mẽ đề nghị sử dụng các giải pháp thứ hai được đề cập bởi C0deH4cker, nếu không bạn có thể có vấn đề tôi đã đề cập trong câu trả lời của tôi. – Tadeck

6

Tất nhiên, bạn có thể vừa in ra đầu ra tiêu chuẩn và thêm vào một tập tin nhật ký, như thế này:

# Uncomment the line below for python 2.x 
#from __future__ import print_function 

import logging 

logging.basicConfig(level=logging.INFO, format='%(message)s') 
logger = logging.getLogger() 
logger.addHandler(logging.FileHandler('test.log', 'a')) 
print = logger.info 

print('yo!') 
5

Thêm một phương pháp là quấn logger trong một đối tượng mà dịch các cuộc gọi đến write đến phương thức log của logger.

Ferry Boender chỉ này, provided under the GPL license trong a post trên his website:

import logging 
import sys 

class StreamToLogger(object): 
    """ 
    Fake file-like stream object that redirects writes to a logger instance. 
    """ 
    def __init__(self, logger, log_level=logging.INFO): 
     self.logger = logger 
     self.log_level = log_level 
     self.linebuf = '' 

    def write(self, buf): 
     for line in buf.rstrip().splitlines(): 
     self.logger.log(self.log_level, line.rstrip()) 

logging.basicConfig(
    level=logging.DEBUG, 
    format='%(asctime)s:%(levelname)s:%(name)s:%(message)s', 
    filename="out.log", 
    filemode='a' 
) 

stdout_logger = logging.getLogger('STDOUT') 
sl = StreamToLogger(stdout_logger, logging.INFO) 
sys.stdout = sl 

stderr_logger = logging.getLogger('STDERR') 
sl = StreamToLogger(stderr_logger, logging.ERROR) 
sys.stderr = sl 

Điều này cho phép bạn dễ dàng định tuyến tất cả đầu ra vào một logger của sự lựa chọn của bạn. Nếu cần, bạn có thể lưu sys.stdout và/hoặc sys.stderr như được đề cập bởi những người khác trong chuỗi này trước khi thay thế nếu bạn cần khôi phục sau.

0

Một lựa chọn đơn giản hơn nhiều,

import logging, sys 
logging.basicConfig(filename='path/to/logfile', level=logging.DEBUG) 
logger = logging.getLogger() 
sys.stderr.write = lambda s: logger.error(s) 
sys.stdout.write = lambda s: logger.info(s) 
+2

Giải pháp này chỉ hoạt động nếu bạn không sử dụng tính năng ghi nhật ký.StreamHandler() để in nhật ký vào màn hình của mình. Bởi vì nếu bạn làm vậy, bạn gửi tin nhắn trong một vòng lặp vô hạn: Trình xử lý luồng cố gắng ghi nó vào sys.stdout.write, nơi nó được chuyển hướng đến trình ghi nhật ký và sau đó một lần nữa đến trình xử lý luồng. – Decrayer

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