2012-12-17 41 views
5

Tôi đang viết một công cụ nghiên cứu và gần đây tôi đã chuyển từ sử dụng các câu lệnh "in" sang sử dụng chức năng nhật ký được tích hợp vào Python. Điều này, tôi lý luận, sẽ cho phép tôi cung cấp cho người dùng tùy chọn bán kết quả đầu ra cho một tệp, ngoài việc bán nó ra màn hình.Đăng nhập từ Ứng dụng Bên ngoài

Cho đến nay rất tốt. Một phần của mã của tôi là trong Python sử dụng "logger.info" và "logger.error" để đổ vào cả màn hình và một tập tin. "logger" là trình ghi log-module. Phần này hoạt động như một sự quyến rũ.

Tuy nhiên, tại một số điểm, tôi sử dụng "subprocess.call" để chạy tệp thi hành thông qua trình bao. Vì vậy, trong suốt mã, tôi có các dòng như

proc = subprocess.call(command) 

Đầu ra từ lệnh này sẽ in ra màn hình, như mọi khi, nhưng nó sẽ không đổ vào tệp mà người dùng đã chỉ định.

Một lựa chọn có thể sẽ mở ra một đường ống đến tập tin:

proc = subprocess.call(command, stdout=f, stderr=subprocess.OUTPUT) 

Nhưng đó sẽ chỉ đổ vào file chứ không phải màn hình.

Về cơ bản, câu hỏi của tôi tóm tắt điều này: có cách nào tôi có thể tận dụng trình ghi nhật ký hiện tại của mình, mà không phải tạo một trình xử lý khác cho các tệp cụ thể cho subprocess.call không? (Có lẽ bằng cách chuyển hướng đầu ra cho logger?) Hoặc là điều này không thể, cho các thiết lập hiện tại? Nếu sau này, làm thế nào tôi có thể cải thiện thiết lập?

(Oh, cũng có thể, nó sẽ là tuyệt vời nếu đăng nhập được trong 'thời gian thực', do đó tin nhắn từ thực thi được ghi lại như họ đang nhận được.)

Nhờ sự giúp đỡ! :)

+1

[StreamLogger class] của Lennart Regebro (http://stackoverflow.com/a/4838875/190597) sẽ hoạt động tốt trong hoàn cảnh của bạn. – unutbu

+0

Cảm ơn bạn đã tham khảo! Điều này làm việc tốt cho trường hợp của tôi. –

Trả lời

3

Thay vì đường ống stdout vào một tệp, bạn có thể đặt ống dẫn đến PIPE, rồi đọc từ PIPE đó và ghi vào nhật ký. Một cái gì đó như thế này:

proc = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.OUTPUT) 
for line in proc.stdout: 
    logging.info(line) 

Tuy nhiên, có một câu trả lời thậm chí đơn giản hơn: Bạn phải sử dụng một đối tượng tập tin giống như với một tập tin xử lý, nhưng bạn có thể tạo một trên đầu trang của ống mà đi mỗi dòng để logging. Bạn có thể tự viết đối tượng này, nhưng, như @unutbu nói, ai đó đã thực hiện nó trong this question. Vì vậy:

with StreamLogger(logging.INFO) as out: 
    proc = subprocess.call(command, stdout=out, stderr=subprocess.OUTPUT) 

Tất nhiên bạn cũng có thể tạm thời quấn stdout ghi vào logger và chỉ cần vượt qua sản lượng thông qua, ví dụ, sử dụng this confusingly identically-named class:

with StreamLogger('stdout'): 
    proc = subprocess.call(command, stderr=subprocess.OUTPUT) 
+0

Cảm ơn bạn đã tham chiếu đến mã trong liên kết cuối cùng. Đó là một chi tiết thú vị. –

3

unutbu's comment là tốt; bạn nên xem Lennart's answer.

Những gì bạn cần là chức năng của tee, nhưng mô-đun subprocess hoạt động ở cấp độ xử lý OS, có nghĩa là dữ liệu được viết bởi quy trình con không thể thấy được bằng mã Python của bạn. giống như đối tượng bạn viết mà các bản ghi và in bất cứ điều gì được ghi vào nó.

Cũng như sử dụng câu trả lời của Lennart, bạn có thể thực hiện việc này bằng thư viện của bên thứ ba như sarge (tiết lộ: Tôi là người duy trì nó). Nó hoạt động cho hơn khai thác gỗ.Giả sử bạn có một chương trình mà tạo ra sản lượng, chẳng hạn như:

# echotest.py 
import time 
for i in range(10): 
    print('Message %d' % (i + 1)) 

và bạn muốn nắm bắt nó trong kịch bản của bạn, đăng nhập nó và in nó vào màn hình:

#subptest.py 
from sarge import capture_stdout 
import logging 
import sys 

logging.basicConfig(filename='subptest.log', filemode='w', 
        level=logging.INFO) 

p = capture_stdout('python echotest.py', async=True) 
while True: 
    line = p.stdout.readline() 
    line = line.strip() 
    # depending on how the child process generates output, 
    # sometimes you won't see anything for a bit. Hence only print and log 
    # if you get something 
    if line: 
     print(line) 
     logging.info(line) 

    # Check to see when we can stop - after the child is done. 
    # The return code will be set to the value of the child's exit code, 
    # so it won't be None any more. 

    rc = p.commands[0].process.poll() 
    # if no more output and subprocess is done, break 
    if not line and rc is not None: 
     break 

Nếu bạn chạy các script trên , bạn nhận được in ra để giao diện điều khiển:

$ python subptest.py 
Message 1 
Message 2 
Message 3 
Message 4 
Message 5 
Message 6 
Message 7 
Message 8 
Message 9 
Message 10 

Và khi chúng tôi kiểm tra các log file, chúng ta thấy:

$ cat subptest.log 
INFO:root:Message 1 
INFO:root:Message 2 
INFO:root:Message 3 
INFO:root:Message 4 
INFO:root:Message 5 
INFO:root:Message 6 
INFO:root:Message 7 
INFO:root:Message 8 
INFO:root:Message 9 
INFO:root:Message 10 
+0

Cảm ơn lời khuyên! :) –

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