2013-02-15 2 views
2

두 스레드 모두 자체 스레드를 사용하여 모두 stdout에 쓰고 있습니다. 이제는 stdout에 많은 쓰레기를 덤프 할 다른 스레드를 추가해야하며이 작업을 원하지 않습니다.stdout을 특정 스레드에 대해서만 파일로 리디렉션

단일 스레드에 대해 stdout을 파일로 리디렉션 할 수있는 방법이 있습니까? 리디렉션 전체 앱 stderr :

업데이트 owobeid에서 언급 한 바와 같이

, 나는 내가 ... 파일에

def startServer(): 
    fd = os.open("foo.txt", os.O_RDWR|os.O_CREAT) 
    fd2 = 2 
    os.dup2(fd, fd2) 

    # rest of the code 

if __name__ == '__main__': 
    threading.Thread(target=startServer).start() 
    raise Exception("My Exception") 

문제를 stderr을 리디렉션하고 ...이 시도. Exception 메시지는 스레드 외부에 있어도 파일로 리디렉션됩니다.

답변

0

dup2을 사용하여 출력을 원하는 파일로 리디렉션하십시오. fd를 파일 설명자로, fd2를 1 (표준 출력)으로 설정하십시오.

참고 : 메인 스레드가 아닌 생성 된 스레드 내부에서 수행하십시오.

+0

표준 출력을 복제 할 수 있습니까?이 점이 어떤 차이가 있습니까? – ATOzTOA

+0

더 나은 그림을 얻으려면 [this] (http://codewiki.wikidot.com/c:system-calls:dup2)를 읽으십시오. – owobeid

+0

내 업데이트 된 질문을 참조하십시오 ... – ATOzTOA

-2

저는 파이썬에 익숙하지 않습니다. 하지만 로그 메시지를 다른 appender (stdout, files 등)로 리다이렉트 (redirect)하기 위해 파이썬에서 로깅 프레임 워크를 사용할 것으로 생각됩니다. 새 스레드는 다른 appender (파일 일 수 있음)를 사용할 수 있으며 다른 스레드는 stdout appender에 로그 할 수 있습니다.

표준 출력 스트림은 프로세스에서 일반적으로 사용되는 것으로 스레드마다 다릅니다.

+0

난 이미 당신이 언급 한 것을 알고있다. 나는 그것을 어떻게 할 것인지를 묻는다. – ATOzTOA

0

단일 스레드에 대해 stdout을 리디렉션 할 수는 없지만 예를 들어 다른 스레드로 쓸 수는 있습니다. 파일을 열고 해당 스레드에서 write()을 호출하십시오. stdout과 stderr는 전체 프로세스에 대한 fd 테이블의 일부인 특정 fds에 매핑되므로, 어느 한 스레드에서 stdout/stderr을 망쳐 버리면 모든 것들이 엉망이됩니다.

그래서이 상황에서 단일 스레드 아래 stdout을 단순히 엉망으로 만들 수는 없습니다. 여전히 바닐라 '인쇄'를 부릅니다. 스폰 된 스레드 및 주 스레드와의 이전 응답에서의 구별은 중요하지 않습니다. 당신은 실제로 별도의 FD로 인쇄 선택의 스레드가 필요합니다

with open('blah', 'w') as f: 
    f.write('bla blah\n') 

그게 당신이 원하는 무엇을 제공하지 않습니다 알아,하지만 나중에 독자이 함께 오는 아는 것이 중요합니다.

개념적으로 도움이되는 것은 인쇄 명령이 후드 아래에서 무엇을하는지 이해하는 것입니다. 본질적으로 fd.write() (modulo 형식 지정법)과 같은 일을하지만 파일 핸들로 stdout을 사용합니다. sys.stdout.write()을 사용하여 직접 해결할 수 있습니다.

1

정확히이 작업을 수행하는 방법을 검색하면서이 포스트를 발견했습니다. Ajax를 사용하여 서버에 요청을 프록시 처리하고 실행중인 스레드에 대한 모든 출력을 반환하는 대화 형 Python 콘솔을 만들고 싶습니다. 나는 그것을 알아 내고 끝내고 나의 해결책을 공유하고 싶었다.

local.LocalProxy이라는 werkzeug 파이썬 라이브러리와 함께 제공되는 클래스가 있는데, 모듈 수준의 함수가 속성처럼 작동 할 수 있습니다. 예를 들어, 이렇게하면 sys.stdout이 정상적으로 작동하지만 LocalProxy 클래스를 통해 프록시가 수행됩니다.

import threading 
import sys 
import cStringIO 
import werkzeug 

thread_proxies = {} 
def redirect(): 
    ident = threading.currentThread().ident 
    thread_proxies[ident] = cStringIO.StringIO() 
    return thread_proxies[ident] 

def proxy(): 
    ident = threading.currentThread().ident 
    return thread_proxies.get(ident, sys.stdout) 

sys.stdout = werkzeug.local.LocalProxy(proxy) 

그리고 어떤 스레드에서 내가 리디렉션하려는, I : 그것은 다른 스레드의 경우

import sys 
import werkzeug 
sys.stdout = werkzeug.local.LocalProxy(lambda: sys.stdout) 

이에 확장, 나는 다음 StringIO 개체를 반환 위의 lambda 대신 함수를 썼다 바로 호출 할 수 있습니다

string_io = redirect() 

그리고 대신에 지금 StringIO 객체에 기록됩니다 sys.stdout에 갈 것 출력을 모두.


기다려라! 나는 sys.stdout, sys.__stdout__, sys.stderrsys.__stderr__을 캡처해야합니다, 그래서 난 내 코드베이스에 stdout_helpers라는이 라이브러리 썼다 :

stdout_helpers.enable_proxy() 
: 내가 전화를 내 응용 프로그램의 시작 부분에서 지금

import threading 
import sys 
import cStringIO 
from werkzeug import local 

# Save all of the objects for use later. 
orig___stdout__ = sys.__stdout__ 
orig___stderr__ = sys.__stderr__ 
orig_stdout = sys.stdout 
orig_stderr = sys.stderr 
thread_proxies = {} 


def redirect(): 
    """ 
    Enables the redirect for the current thread's output to a single cStringIO 
    object and returns the object. 

    :return: The StringIO object. 
    :rtype: ``cStringIO.StringIO`` 
    """ 
    # Get the current thread's identity. 
    ident = threading.currentThread().ident 

    # Enable the redirect and return the cStringIO object. 
    thread_proxies[ident] = cStringIO.StringIO() 
    return thread_proxies[ident] 


def stop_redirect(): 
    """ 
    Enables the redirect for the current thread's output to a single cStringIO 
    object and returns the object. 

    :return: The final string value. 
    :rtype: ``str`` 
    """ 
    # Get the current thread's identity. 
    ident = threading.currentThread().ident 

    # Only act on proxied threads. 
    if ident not in thread_proxies: 
     return 

    # Read the value, close/remove the buffer, and return the value. 
    retval = thread_proxies[ident].getvalue() 
    thread_proxies[ident].close() 
    del thread_proxies[ident] 
    return retval 


def _get_stream(original): 
    """ 
    Returns the inner function for use in the LocalProxy object. 

    :param original: The stream to be returned if thread is not proxied. 
    :type original: ``file`` 
    :return: The inner function for use in the LocalProxy object. 
    :rtype: ``function`` 
    """ 
    def proxy(): 
     """ 
     Returns the original stream if the current thread is not proxied, 
     otherwise we return the proxied item. 

     :return: The stream object for the current thread. 
     :rtype: ``file`` 
     """ 
     # Get the current thread's identity. 
     ident = threading.currentThread().ident 

     # Return the proxy, otherwise return the original. 
     return thread_proxies.get(ident, original) 

    # Return the inner function. 
    return proxy 


def enable_proxy(): 
    """ 
    Overwrites __stdout__, __stderr__, stdout, and stderr with the proxied 
    objects. 
    """ 
    sys.__stdout__ = local.LocalProxy(_get_stream(sys.__stdout__)) 
    sys.__stderr__ = local.LocalProxy(_get_stream(sys.__stderr__)) 
    sys.stdout = local.LocalProxy(_get_stream(sys.stdout)) 
    sys.stderr = local.LocalProxy(_get_stream(sys.stderr)) 


def disable_proxy(): 
    """ 
    Overwrites __stdout__, __stderr__, stdout, and stderr with the original 
    objects. 
    """ 
    sys.__stdout__ = orig___stdout__ 
    sys.__stderr__ = orig___stderr__ 
    sys.stdout = orig_stdout 
    sys.stderr = orig_stderr 

을 그리고

그리고 어떤 스레드에서 지금 전화는 :

string_io = stdout_helpers.redirect() 
관련 문제