TclOO:class 记录器混合
TclOO: class logger mixin
请推荐 TclOO class 记录器 mixin/trait。
tcllib 1.19 中包含的记录器在用作 class 记录器时中断:
#!/usr/bin/env tclsh
package require logger
package require logger::utils
::oo::class create Main {
variable log
constructor {} {
set this_inst [namespace current]
set this_klaz [info object class $this_inst]
set log [::logger::init $this_klaz]
::logger::utils::applyAppender \
-appender "console" \
-appenderArgs {-conversionPattern {%d \[%p\] \[%M\] %m}} \
-serviceCmd $log
}
method invoke {} {
${log}::info "hello"
}
}
set main [Main new]
$main invoke
正在生成对象命名空间:
2018/05/15 08:54:43 [info] [::oo::Obj12] hello
而不是 class/method 命名空间:
2018/05/15 08:54:43 [info] [::Main::invoke] hello
这是 loggerUtils.tcl 中 ::logger::utils::createLogProc
中的 bug,因为 %M
替换不知道 TclOO。如果是,它就不会使用调用该方法的对象的名称,而是使用方法的名称。 (看起来它是为与 [incr Tcl] 一起工作而设计的,它 确实 命名方法,就像您想要的那样。)
理想情况下,您应该为每个 class 设置一次记录器,而不是为每个实例设置一次。以下是您的操作方式:
package require logger
package require logger::utils
::oo::class create Main {
variable log
self {
variable log
method init {} {
set log [::logger::init [self]]
::logger::utils::applyAppender \
-appender "console" \
-appenderArgs {-conversionPattern {%d \[%p\] \[%M\] %m}} \
-serviceCmd $log
}
method logger {} {return $log}
}
constructor {} {
set log [[self class] logger]
}
method invoke {} {
${log}::info "hello"
}
}
Main init
set main [Main new]
$main invoke
但这并不能修复错误。这实际上是因为它查找 %M
替换的值,如下所示:
if {[info level] < 2} {
set method "global"
} else {
set method [lindex [info level -1] 0]
}
而它可能应该做更多像这样的事情:
if {[info level] < 2} {
set method "global"
} elseif {[uplevel 1 {namespace which self}] == "::oo::Helpers::self"} {
set method [uplevel 1 {string cat [self class] "::" [self method]}]
} else {
set method [lindex [info level -1] 0]
}
模式#1:提供命令到方法转发器。
混音:
::oo::class create WithLogger {
self {
variable klaz_log
method init_log {} {
variable klaz_log [::logger::init [self]]
::logger::utils::applyAppender ... $klaz_log
}
method klaz_log {} {
return $klaz_log
}
}
method withLogger {} {
set this_klaz [self class]
$this_klaz init_log
set klaz_log [$this_klaz klaz_log]
{*}"proc log {level args} {tailcall ${klaz_log}::${level} {*}$args}"
}
}
用法:
::oo::class create Main {
mixin -append WithLogger
constructor {} {
my withLogger ; # needs setup
}
method invoke {} {
log info "hello" ; # uses command-to-method forwarder
}
}
set main [Main new]
$main invoke
输出:
2018/05/16 15:08:59 [info] [::Main::invoke] hello
请推荐 TclOO class 记录器 mixin/trait。
tcllib 1.19 中包含的记录器在用作 class 记录器时中断:
#!/usr/bin/env tclsh
package require logger
package require logger::utils
::oo::class create Main {
variable log
constructor {} {
set this_inst [namespace current]
set this_klaz [info object class $this_inst]
set log [::logger::init $this_klaz]
::logger::utils::applyAppender \
-appender "console" \
-appenderArgs {-conversionPattern {%d \[%p\] \[%M\] %m}} \
-serviceCmd $log
}
method invoke {} {
${log}::info "hello"
}
}
set main [Main new]
$main invoke
正在生成对象命名空间:
2018/05/15 08:54:43 [info] [::oo::Obj12] hello
而不是 class/method 命名空间:
2018/05/15 08:54:43 [info] [::Main::invoke] hello
这是 loggerUtils.tcl 中 ::logger::utils::createLogProc
中的 bug,因为 %M
替换不知道 TclOO。如果是,它就不会使用调用该方法的对象的名称,而是使用方法的名称。 (看起来它是为与 [incr Tcl] 一起工作而设计的,它 确实 命名方法,就像您想要的那样。)
理想情况下,您应该为每个 class 设置一次记录器,而不是为每个实例设置一次。以下是您的操作方式:
package require logger
package require logger::utils
::oo::class create Main {
variable log
self {
variable log
method init {} {
set log [::logger::init [self]]
::logger::utils::applyAppender \
-appender "console" \
-appenderArgs {-conversionPattern {%d \[%p\] \[%M\] %m}} \
-serviceCmd $log
}
method logger {} {return $log}
}
constructor {} {
set log [[self class] logger]
}
method invoke {} {
${log}::info "hello"
}
}
Main init
set main [Main new]
$main invoke
但这并不能修复错误。这实际上是因为它查找 %M
替换的值,如下所示:
if {[info level] < 2} {
set method "global"
} else {
set method [lindex [info level -1] 0]
}
而它可能应该做更多像这样的事情:
if {[info level] < 2} {
set method "global"
} elseif {[uplevel 1 {namespace which self}] == "::oo::Helpers::self"} {
set method [uplevel 1 {string cat [self class] "::" [self method]}]
} else {
set method [lindex [info level -1] 0]
}
模式#1:提供命令到方法转发器。
混音:
::oo::class create WithLogger {
self {
variable klaz_log
method init_log {} {
variable klaz_log [::logger::init [self]]
::logger::utils::applyAppender ... $klaz_log
}
method klaz_log {} {
return $klaz_log
}
}
method withLogger {} {
set this_klaz [self class]
$this_klaz init_log
set klaz_log [$this_klaz klaz_log]
{*}"proc log {level args} {tailcall ${klaz_log}::${level} {*}$args}"
}
}
用法:
::oo::class create Main {
mixin -append WithLogger
constructor {} {
my withLogger ; # needs setup
}
method invoke {} {
log info "hello" ; # uses command-to-method forwarder
}
}
set main [Main new]
$main invoke
输出:
2018/05/16 15:08:59 [info] [::Main::invoke] hello