1 # vim: ft=tcl foldmethod=marker foldmarker=<<<,>>> ts=4 shiftwidth=4
5 variable baselog_threshold
""
6 variable baselog_instancename
""
10 variable debuglogmode
0
12 method log
{lvl
{msg
""} args
}
20 common using_hotfuncs
0
43 proc remote_logging
{ip port
} {
44 set remote
[socket $ip $port]
45 fconfigure $remote -translation binary -encoding binary -blocking 1 -buffering none
48 proc load_classmap
{fn
} {
49 if {[catch {set fp
[open $fn r
]} errmsg
]} {
50 error "Problem opening classmap file: $errmsg"
56 array set tmp
[tlc
::decomment $dat]
58 error "Error parsing classmap: should be a list of key value pairs, optionally commented"
61 foreach {key val
} [array get tmp
] {
62 if {[info exists lvlmap
($val)]} {
65 if {![string is integer
-strict $val]} {
66 error "Log threshold for $key is not an integer or a valid symbolic level ($val)"
68 set classmap
($key) $val
72 proc load_hotfuncs
{fn
} {
73 if {[catch {set fp
[open $fn r
]} errmsg
]} {
74 error "Problem opening hotfuncs file: $errmsg"
80 array set tmp
[tlc
::decomment $dat]
82 error "Error parsing hotfuncs: should be a list of key value pairs, optionally commented"
85 foreach {key val
} [array get tmp
] {
86 if {[info exists lvlmap
($val)]} {
89 if {![string is integer
-strict $val]} {
90 error "Log threshold for $key is not an integer or a valid symbolic level ($val)"
92 set hotfuncs
($key) $val
98 proc timestamp_function
{func
} {
99 array unset helpers timestamp
102 array unset helpers timestamp
104 set helpers
(timestamp
) $func
109 return [clock microseconds
]
112 proc output_function
{func
} {
113 set helpers
(output
) $func
116 proc redir_output
{cb
} {
122 body tlc
::Baselog::log {lvl
{msg
""} args
} { #<<<1
123 if {$debuglogmode} {puts stderr
"foo"}
124 # Get a timestamp <<<
125 set now
[clock microseconds
]
126 #if {[info exists helpers(timestamp)]} {
127 # set cmd [linsert [lrange $helpers(timestamp) 1 end] 0 \
128 # [lindex $helpers(timestamp) 0]]
129 # set now [uplevel #0 $cmd]
131 # if {[package vsatisfies [info tclversion] 8.5]} {
132 # set now [clock microseconds]
134 # set now [expr {[clock seconds] * 1000000}]
137 # Get a timestamp >>>
142 array set switches
$args
143 if {[info exists switches
(-suppress)]} {
144 set switches
(-suppressed) $switches(-suppress)
146 if {![string is integer
-strict $lvl]} {
147 if {![info exists lvlmap
($lvl)]} {
150 set lvl
$lvlmap($lvl)
154 set caller_inf
[info level
-1]
155 set name
[lindex $caller_inf 0]
156 set passed_args
[lrange $caller_inf 1 end
]
158 set fqname
"<unknown>"
159 set caller_args_def
{}
160 for {set i
1} {$i <= [llength $passed_args]} {incr i
} {
161 lappend caller_args_def
"<unknown$i>"
164 set fqname
[uplevel 1 [list namespace origin
$name]]
165 if {$name eq
"namespace"} {
166 set caller_args_def
{}
168 set caller_args_def
[uplevel 1 [list info args
$name]]
172 set logzone
[namespace qualifiers
$fqname]
174 if {$debuglogmode} {puts stderr
"bar"}
175 if {[info exists helpers
(output
)]} {
176 set output_cmd
[linsert [lrange $helpers(output
) 1 end
] 0 \
177 [lindex $helpers(output
) 0]]
179 set ns
[namespace qualifiers
$logzone]
180 set class
[namespace tail
$logzone]
181 set method
[namespace tail
$fqname]
183 set substmap
[list "\n" "%n" "\t" "%t" "%" "%%"]
186 foreach arg
$caller_args_def {
187 if {$arg == "args"} {
188 set this_passed_arg
[lrange $passed_args $idx end
]
190 set this_passed_arg
[lindex $passed_args $idx]
193 set alen
[string length
$this_passed_arg]
194 if {$arg in
$switches(-suppressed)} {
195 set this_passed_arg
"#<suppressed>"
196 set this_passed_arg_type
[list info suppressed
]
197 } elseif
{$this_passed_arg eq
""} {
198 set this_passed_arg
"{}"
199 set this_passed_arg_type
[list info blank
]
200 } elseif
{$alen > 23} {
201 set this_passed_arg
[string range
$this_passed_arg 0 21]
202 set this_passed_arg
[string map
$substmap $this_passed_arg]
203 set this_passed_arg_type
[list value_trunc
$alen]
204 } elseif
{![string is print
$this_passed_arg]} {
205 set this_passed_arg
"#<nonprint($alen)>"
206 set this_passed_arg_type
[list info nonprint
]
208 set this_passed_arg
[string map
$substmap $this_passed_arg]
209 set this_passed_arg_type
[list value_whole
$alen]
212 lappend argdesc
[list $arg $this_passed_arg $this_passed_arg_type]
216 #uplevel #0 [list {*}$helpers(output) $now $baselog_instancename $ns $class $method $argdesc $lvl $msg [tlc::build_stackdump]]
217 uplevel #0 [list {*}$helpers(output) $now $baselog_instancename $ns $class $method $argdesc $lvl $msg]
219 if {$baselog_threshold != ""} {
220 set threshold
$baselog_threshold
221 } elseif
{[info exists classmap
($logzone)]} {
222 set threshold
$classmap($logzone)
224 set threshold
$::tlc::log(threshold
)
227 if {$lvl < $threshold} {
228 if {!($using_hotfuncs)} return
230 # Check our callers for a hotfunc <<<
232 set i
[expr {[info level
] - 1}]
240 set stackname
[lindex [info level
$i] 0]
241 if {$stackname == {}} continue
243 set fqname
[uplevel $depth [list namespace origin
$stackname]]
245 set fqname
"??$stackname"
248 if {[info exists hotfuncs
($fqname)]} {
249 set threshold
$hotfuncs($fqname)
250 if {$lvl >= $threshold} break
253 if {$lvl < $threshold} return
254 # Check our callers for a hotfunc >>>
257 if {$baselog_instancename != ""} {
258 set instance_prefix
"[c red]$baselog_instancename[c norm] "
260 set instance_prefix
""
262 set ns
[namespace qualifiers
$logzone]
263 set class
[namespace tail
$logzone]
264 set method
[namespace tail
$fqname]
265 set fqname_coloured
"${instance_prefix}${ns}::[c red]$class[c norm]::[c bright yellow]$method[c norm]"
267 set substmap
[list "\n" "[c purple]\\n[c white]" "\t" "[c purple]\\t[c white]"]
270 foreach arg
$caller_args_def {
271 if {$arg == "args"} {
272 set this_passed_arg
[lrange $passed_args $idx end
]
274 set this_passed_arg
[lindex $passed_args $idx]
277 set alen
[string length
$this_passed_arg]
278 if {[lsearch $switches(-suppressed) $arg] != -1} {
279 set this_passed_arg
"#<suppressed>"
280 } elseif
{$this_passed_arg == ""} {
281 set this_passed_arg
"{}"
282 } elseif
{$alen > 23} {
283 set this_passed_arg
[string range
$this_passed_arg 0 21]
284 set this_passed_arg
[string map
$substmap $this_passed_arg]
285 set this_passed_arg
"[c underline bright white]$this_passed_arg[c norm]/[c red]$alen[c norm]"
286 } elseif
{![string is print
$this_passed_arg]} {
287 set this_passed_arg
"#<nonprint($alen)>"
289 set this_passed_arg
[string map
$substmap $this_passed_arg]
290 set this_passed_arg
"[c underline bright white]$this_passed_arg[c norm]"
293 lappend argdesc
"[c green]$arg[c norm]$this_passed_arg"
297 set argtext
[join $argdesc " "]
299 set outmsg
"${fqname_coloured} $argtext"
301 set fg
"bright white"
304 } elseif
{$lvl >= 30} {
306 } elseif
{$lvl >= 20} {
310 } elseif
{$lvl >= 10} {
316 append outmsg
": [c bg_$bg $fg]$msg[c norm]"
319 if {[info exists redir
] && $redir != ""} {
320 uplevel #0 [list $redir $outmsg]
321 } elseif
{[info exists remote
]} {
327 if {$debuglogmode} {puts stderr
"baz"}
331 body tlc
::Baselog::c {args
} { #<<<1
332 return [tlc
::colour {*}$args]
336 body tlc
::Baselog::parray {args
} { #<<<1
337 switch -- [llength $args] {
339 uplevel [list ::parray [lindex $args 0]]
343 set lvl
[lindex $args 0]
344 set arrname
[lindex $args 1]
347 set keys
[array names a
]
351 set thislen
[string length
$key]
352 if {$thislen > $maxlen} {
357 incr maxlen
[string length
$arrname]
361 foreach key
[lsort $keys] {
362 append msg
[format "%-${maxlen}s = \"%s\"\n" "${arrname}($key)" $a($key)]
365 uplevel [list log
$lvl $msg]
369 error "Invalid number of arguments, expecting lvl arrayvar" "" \