::nsmcp::FileLogSource ::nsmcp::FileLogSource appendText consume emptyState init joinLine read ::nsmcp::LogSource ::nsmcp::LogSource read ::nsmcp::FileLogSource->::nsmcp::LogSource ::nsmcp::CachedLogSearch ::nsmcp::CachedLogSearch encodeEvent flush init lineStart physicalLine record recordStart removeQueries results search temporaryFile ::nsmcp::CachedLogSearch->::nsmcp::FileLogSource

Class ::nsmcp::FileLogSource

::nsmcp::FileLogSource[i] create ... \
           [ -cacheKey cacheKey ] \
           [ -maxEvents:integer (default "1000") ] \
           [ -maxMessageBytes:integer (default "65536") ] \
           [ -maxReadBytes:integer (default "1048576") ] \
           [ -mutex (default "") ] \
           [ -path:required path:required ] \
           [ -recordParser (default "::nsmcp::logRecordParser") ] \
           [ -store:required store:required ]

Defined in /usr/local/ns/tcl/nsmcp/lib/log-source.tcl

Class Relations

  • class: ::nx::Class[i]
  • superclass: ::nsmcp::LogSource[i]
  • subclass: ::nsmcp::CachedLogSearch[i]
::nx::Class create ::nsmcp::FileLogSource \
     -superclass ::nsmcp::LogSource

Methods (to be applied on instances)

  • read (scripted, public)

     <instance of nsmcp::FileLogSource[i]> read

    Testcases:
    No testcase defined.
    ns_mutex lock ${:mutex}
    try {
        file stat ${:path} before
        set channel [open ${:path} rb]
        try {
            fconfigure $channel -translation binary -encoding binary
            file stat ${:path} opened
            if {[list $before(dev) $before(ino)] ne [list $opened(dev) $opened(ino)]} {
                error "log file changed while opening; retry"
            }
            set identity [list $before(dev) $before(ino)]
            set reset false
            set generation 1
            if {[nsv_exists ${:store} ${:cacheKey}] && [nsv_get ${:store} ${:cacheKey} state]} {
                set generation [dict get $state generation]
                set prefix [dict get $state prefix]
                # A fixed prefix also detects common copytruncate-and-regrow
                # cases that have already grown beyond the saved cursor.
                set prefixNow [read $channel [string length $prefix]]
                if {$identity ne [dict get $state identity] ||
                    $before(size) < [dict get $state cursor] || $prefixNow ne $prefix} {
                    set reset true
                    incr generation
                }
            } else {
                set reset true
            }
            if {$reset} {
                seek $channel 0
                set prefix [read $channel [expr {min(256, $before(size))}]]
                set state [:emptyState $identity $generation $prefix]
            }
            if {[dict get $state prefix] eq "" && $before(size) > 0} {
                seek $channel 0
                dict set state prefix [read $channel [expr {min(256, $before(size))}]]
            }
            seek $channel [dict get $state cursor]
            # Read only bytes visible at the snapshot, within the work budget.
            set count [expr {min(${:maxReadBytes}, max(0, $before(size)-[dict get $state cursor]))}]
            set state [:consume $state [read $channel $count]]
            file stat ${:path} after
            seek $channel 0
            set prefix [dict get $state prefix]
            set prefixAfter [read $channel [string length $prefix]]
            if {[list $after(dev) $after(ino)] ne $identity ||
                $after(size) < $before(size) || $prefixAfter ne $prefix} {
                # Do not publish a mixed snapshot if rotation races this read.
                error "log file changed during read; retry"
            }
            nsv_set ${:store} ${:cacheKey} $state
            set events [dict get $state events]
            if {[dict get $state pending] ne ""} {lappend events [dict get $state pending]}
            set events [lrange $events end-[expr {${:maxEvents}-1}] end]
            return [dict create generation $generation reset $reset  cursor [dict get $state cursor]  backlogBytes [expr {max(0, $before(size)-[dict get $state cursor])}]  partialLineBytes [expr {[dict get $state cursor]-[dict get $state fragmentOffset]}]  events $events]
        } finally {close $channel}
    } finally {ns_mutex unlock ${:mutex}}