2011-11-07 4 views
1

내 멀티 스레드 Tcl 응용 프로그램에 대한 로깅 라이브러리가 필요합니다. 표준 logger 패키지를 사용할 수 있습니까? 가능한 경우 멀티 스레딩 환경에 어떤 제한이 적용됩니까?Tcl 용 스레드 안전 로거

가능한 경우 스레드간에 로깅 을 공유하고 싶습니다.

감사

+0

http://tcllib.sourceforge.net/doc/logger.html http://code.activestate.com/lists/tcl-core/10866/ –

+0

첫 번째 링크는 사용하기에는 너무 저조한 표현입니다. 두 번째 링크는 내 질문에서 언급 한 표준 로거 라이브러리를 참조합니다. 실제로 스레드로부터 안전합니까? – Andrey

답변

3

Tcl 스레드는 데이터를 공유하지 않고 (스레드 패키지의 특정 기능을 명시 적으로 사용하지 않는 한) 메시지 전달을 통해 통신합니다. 따라서 전용 로거 (logging logger) 스레드를 설정하고 작업자 스레드에서 메시지를 로깅 대기열로 보내는 것이 방법이 될 것 같습니다.

그렇지 않으면 경합 지점은 실제로 데이터를 기록하기 위해 로거에서 사용되는 OS 리소스의 어딘가에있을 것입니다.

업데이트이 좋아, 내가 실제로 구현하기 위해 제안 된 어떤 작업 스케치입니다 :

package require Tcl 8.5 
package require Thread 

proc make_worker_thread {logger_id body} { 
    set newbody [list set ::logger $logger_id] 
    append newbody \n { 
    proc ::log {severity msg} { 
     global logger 
     thread::send $logger [list ::log $severity $msg] 
    } 
    } \n $body 
    thread::create $newbody 
} 

set logger [thread::create { 
    package require logger 

    proc log {severity msg} { 
    puts "hey, that's it: ($severity) $msg" 
    } 

    puts "logger thread created: [thread::id]" 

    thread::wait 
}] 

for {set i 0} {$i < 3} {incr i} { 
    make_worker_thread $logger { 
    proc post_msg {} { 
     log notice "A message from [thread::id]" 
     after 1000 ::post_msg 
    } 

    puts "worker thread created: [thread::id]" 

    after 1000 ::post_msg 

    thread::wait 
    } 
} 

vwait forever 

이 코드는 각 게시물의 로거 스레드에 메시지 한 번 당 하나 개의 로거 스레드 및 네 개의 작업자 스레드를 생성 둘째. 코드는 수동으로 중단 될 때까지 실행됩니다. 로거 스레드는 콘솔에 전달 된 메시지를 단순하게 출력하지만,이 스레드의 다른 누군가가 이미 언급했듯이, Tcllib의 "logger"패키지를 사용할 수 있습니다 (시설과 같은 멋진 물건이 필요한 경우).

내 지점을 유지하려면

  • 로거 패키지 자체는 아마도 스레딩에 대해 아무것도 알지 못한다.
  • Tcl 스레드는 잘 분리되어 있으며 일반적으로 메시지 전달을 통해 통신합니다.
  • 따라서 로거 용 스레드를 만들고 작업자 스레드가 메시지를 보내도록하십시오. 따라서 작업 스레드는 로거가 구현되는 방식과 관련이 없습니다.

P. 작업자 스레드에서 [thread::send -async ...]을 사용하여 로그 메시지를 완전히 비동기로 보낼 수 있습니다. 그것은 당신이 로거의 다중 스레드를 사용하여 달성하려는 작업에 조금 따라

# replacement for logger::init procedure from logger package 
proc ::mylogger::init { service } { 
    set log [logger::init $service] 

    foreach lvl [logger::levels] { 
    interp alias {} log_to_file_$lvl {} ::mylogger::log $lvl $service 
    ${log}::logproc $lvl log_to_file_$lvl 
    } 

    return $log 
} 

proc mylogger::server { } { 
    set t [thread::create { 

    proc log { level txt } { 
     set msg "\[[clock format [clock seconds] -format "%Y-%m-%dT%H:%M:%S"]\]\t$level\t$txt" 
     puts stderr $msg 
    } 

    # enter to event loop 
    thread::wait 
    }] 

    tsv::set measure-logger loggerThread $t 
} 

proc ::mylogger::log { level service txt } { 
    set t [tsv::get measure-logger loggerThread] 
    thread::send -async $t [list log $level "$service\t$txt"] 
} 

# EXAMPLE 

# start logging thread 
# should be called once from main application thread 
::mylogger::server 

# create logger 
# may be called from any thread 
set log [mylogger::init myservice] 

# log a message 
# may be called from the thread the "mylogger::init myservice" was called in 
${log}::debug myservice "Hello, World!" 

# wait a second 
after 1000 
+0

감사합니다. 이것은 해결책으로 들립니다. 그런 전용 로깅 스레드의 기존 및 강력한 구현을 알고 있습니까? – Andrey

+0

@Andrey, 왜 그게 필요하겠습니까? 그것은 간단하게 생각하지 않는 것 같습니다 : 기본적으로 새 스레드를 생성 한 다음 그 "로거"패키지를로드하고 부트 스트랩 한 다음 이벤트 루프를 입력하십시오. 다른 쓰레드는 그 쓰레드의 id에'thread :: send'를 사용합니다. http://wiki.tcl.tk/Thread – kostix

+0

에서 시작하십시오. 로거 패키지를 멀티 스레딩과 통합하려고합니다. 그리고 다른 누군가가 이미이 작업을 수행 한 경우 로거의 내부 구조를 조사하고 싶지 않습니다. – Andrey

1

A Logging API for Tcl

이 구현은 스레드 안전합니다. 일반적으로 목적으로 C 함수에는 tcl 해석기가 필요하지 않습니다.

+0

실제 코드에 대한 링크가 표시되지 않습니다. – kostix

+0

답장을 보내 주셔서 감사합니다. 다운로드 가능한 아카이브 및 문서에 대한 링크는 어디에서 찾을 수 있습니까? 이메일로 개발자에게 문의해야합니까? – Andrey

+0

http://sourceforge.net/projects/tcllib/files/tcllib/1.13/ –

0

여기 logger 패키지 내 "멀티 스레딩"래퍼입니다.

로그 메시지를 디스크에 기록하는 동안 작업자 스레드를 차단하지 않는 유스 케이스가 있다면 가장 간단한 방법은 logger를 정상적으로 사용하고 간단한 logproc을 구성하여 thread :: send -async를 일부 로깅 스레드로 설정하는 것입니다 (실제로는 appender로 logger를 사용하여 실제 로그 파일을 작성합니다)를 로그 메시지와 함께 사용합니다 (기본적으로 수용된 응답에서 스케치 된 내용).

로거 옵션을 사용하여 전체 프로그램에 대한 로깅을 사용/사용하지 않으려면 다양한 스레드에서 사용자 정의 lvlchangeproc를 통해 모든 스레드에 변경 사항을 전파해야합니다.

+0

아마 작동합니다. ':: mylogger : log'에서'tsv :: get' 접근 방식은 다소 모호한 것처럼 보입니다. 단순히 각 로깅 호출에서'tsv :: get'을 호출하는 대신에 올바른 스레드 ID를 가진 사용자 정의 proc 파일을 생성 할 것입니다. 가장 쉬운 방법은 로깅 별칭을 설정하는':: mylogger :: init' proc 파일을 사용하는 것입니다. 별칭에 고정 된 4 번째 매개 변수로 스레드 ID를 추가하기 만하면됩니다. – schlenk

+0

귀하의 제안은 합리적인, 감사합니다. – Andrey