Tcl的线程安全记录器

时间:2011-11-07 14:24:03

标签: multithreading logging tcl

我需要一个用于多线程Tcl应用程序的日志库。我可以使用标准logger包裹吗?如果可以的话,在多线程环境中应用了哪些限制?

如果可能,我想在线程之间共享日志记录 services

由于

4 个答案:

答案 0 :(得分:3)

Tcl线程不共享数据(除非您明确使用Thread包中的某些工具),而是通过消息传递进行通信。因此,似乎要采用的方法是设置一个专用的“记录器”线程,并将记录消息从工作线程中排入队列。

否则争用点可能会出现在记录器用来实际写入数据的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.S。在工作线程中,您可以使用[thread::send -async ...]使发送日志消息完全异步。

答案 1 :(得分:1)

A Logging API for Tcl

此实现是线程安全的。因为一般 目的,C函数不需要tcl-interpreter。

答案 2 :(得分:0)

这是logger包的“多线程”包装器:

# 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

答案 3 :(得分:0)

这取决于您想要通过多线程使用记录器实现的目标。

如果您只是让用例在将日志消息写入磁盘时不阻塞您的工作线程,最简单的方法是正常使用logger并配置一个简单的logproc,它将一个thread :: send -async执行到一些日志记录线程(它本身可以使用带有appender的记录器来编写实际的日志文件)和你的日志消息(基本上已经在接受的答案中勾勒出来)。

如果你想使用loggers选项来禁用/启用整个程序的日志记录,那么你需要做更多工作,通过自定义lvlchangeproc来将loglevel更改传播到所有线程。