Class ::nsmcp::AccessFileSummaryTool (public)

 ::nx::Class ::nsmcp::AccessFileSummaryTool[i]

Defined in /usr/local/ns/tcl/nsmcp/log-traffic-summary.tcl

Testcases:
No testcase defined.
Source code:
    :property {name access_log_summary}
    :property {description {Scan configured access-log files in a background job, independent of cache retention. Failed-traffic analysis supports status OR statusClass, exact pool/method and recordSource (all/driver/connection/unknown). All selected counts, rankings, origins and samples are computed after filters. context counts the same scanned time/path/pool/method/source traffic before status filtering; trafficBuckets provide up to 50 busiest occupied buckets with explicit omissions. Use bucketSeconds 1 for short bursts (at most 3600 buckets); default about 60 buckets. Driver pool and protocol-module labels come from the log header only. Driver names are reused threads, not unique request IDs. Driver 503 does not prove queue-full; queueFullReasonAvailable is false. Driver synthetic timing phases never enter timing averages; unavailableTimingCount is separate from timestamp fallbackCount. statusTimings separate admitted-worker measurements by response status. Default selection ordered reads endpoint records and seeks by request-start timestamps under an explicit approximate ordering assumption, with five seconds of selection padding filtered against the original bounds; completion timestamps are fallback values. Observed inversions exceeding five seconds or unusable probes fall back to bounded scanning. This does not certify unsampled ordering or include every delayed completion. Use selection exhaustive for full verification. For prompt origin hints start with mode evidence (default 5000 matching records, at most 50000 parsed candidates, 32MiB byte budget, maxRecords 1..10000). Its bounded prefix rankings describe only the observed evidence span, not the entire requested interval; follow with mode summary only when full counts are needed. Poll log_results with jobHandle until complete; the result is a summary, not record pages. Omit pathLiteral for all parsed request paths, including empty or non-slash targets. Use pathLiteral ".php" for case-sensitive literal substring matching on the logged queryless path, never query values; no regexp or URL decoding. Defaults to today UTC; set timezone for today/yesterday, or lastMinutes, or explicit from/to. includeRotations defaults true and includes recognized numbered/dated siblings and gzip rotations. ASCII literals use bounded ns_fseekchars candidate searches; Unicode/ANSI cases retain conservative parsing. In exhaustive selection, a bounded server-local time index stores exhaustive start-time bounds for byte ranges independently of path filters. It skips unrelated rotations and seeks over disjoint ranges without assuming timestamp order. Cold scans build the index; changed/append-only snapshots verify complete cached ranges by digest before exclusion, counting verification reads against the scan budget. Unknown, malformed, oversized and unindexed ranges are scanned. Cache metadata is bounded and lost on process restart; filenames and endpoint samples never prove absence. coverage.rotationsSkippedOutsideWindow and eligibleFilesFullyExamined distinguish verified pruning from missing coverage. Parsing diagnostics in literal mode concern candidates and fallback rows, not every unrelated record. Fixed snapshots, bounded streaming/decompression, file/byte/cardinality limits and changed/unreadable files are reported. Counts use logged request start time, falling back to completion time; end is exclusive. Returns all-match totals before bounded path, method, status, pool, UTC-hour, redacted User-Agent and address-free peer-concentration rankings, authentication states, timing totals and distributed samples including status below 400. When a native SQLite aggregation pool is configured (accessAggregationPool, falling back to databasePool), peers and full User-Agent identity hashes are counted in a private per-job SQLite spool with bounded buffers and disk budget. Otherwise aggregateStorage explicitly reports bounded-memory fallback. maxGroups 1..50 limits rankings, not scanning. Inspect aggregateStorage status/reason, breakdowns storageOmittedRecords separately from capacity/ranking omissions, exact observedDistinctPeers/observedDistinctUserAgents and peerConcentration top1/top10/top100 shares. Exactness concerns scanned matching records, not retention or verified identities. Unknown values, clipped/redacted labels, storage failures and ranking omissions are separate. Counts are access records, not unique requests/incidents. No user IDs, peer addresses, query strings or caller-supplied filenames are exposed. sourceFullyExamined does not certify full-day retention; windowComplete remains false without verified rotation history.}}
    :property {inputSchema {{"type":"object","properties":{"selection":{"type":"string","enum":["ordered","exhaustive"],"default":"ordered","description":"ordered uses endpoint start times and byte bisection, assuming sorted start times; exhaustive retains full scanning/index verification"},"mode":{"type":"string","enum":["summary","evidence"],"default":"summary"},"maxRecords":{"type":"integer","minimum":1,"maximum":10000,"default":5000,"description":"Maximum matching records in evidence mode; a separate candidate ceiling is max(50000,10*maxRecords). Results are a bounded prefix, not an unbiased window distribution"},"pathLiteral":{"type":"string","minLength":1,"maxLength":256,"description":"Case-sensitive literal substring in the logged queryless path, at most 256 UTF-8 bytes; no regexp or decoding"},"includeRotations":{"type":"boolean","default":true},"period":{"type":"string","enum":["today","yesterday"]},"timezone":{"type":"string"},"lastMinutes":{"type":"integer","minimum":1,"maximum":10080},"from":{"type":"integer","minimum":0},"to":{"type":"integer","minimum":1},"maxGroups":{"type":"integer","minimum":1,"maximum":50},"status":{"type":"integer","minimum":100,"maximum":599,"description":"Exact HTTP response status; mutually exclusive with statusClass"},"statusClass":{"type":"string","enum":["1xx","2xx","3xx","4xx","5xx","4xx/5xx"],"description":"Response status class; 4xx/5xx selects all failed responses. Mutually exclusive with status"},"pool":{"type":"string","minLength":1,"maxLength":128,"description":"Exact case-sensitive pool, including driver pool suffixes; unknown is explicit"},"method":{"type":"string","minLength":1,"maxLength":32,"description":"Exact uppercase HTTP method"},"recordSource":{"type":"string","enum":["all","driver","connection","unknown"],"default":"all","description":"Driver identifies synthetic driver-side access records, not a unique request or proven queue-full reason"},"bucketSeconds":{"type":"integer","minimum":1,"description":"Positive seconds, at most 3600 buckets; default about 60 buckets across the window. Returns top 50 occupied buckets with omission counts."}},"additionalProperties":false}}}
    :method options {arguments} {
        if {[lindex $arguments 1] ne "object"} {error "Expected arguments object"}
        set base {}; set seen {}; set extras {pathLiteral {} includeRotations true selection ordered mode summary maxRecords 5000}
        foreach {key type value} [lindex $arguments 2] {
            if {$key in $seen} {error "Duplicate access summary argument"}; lappend seen $key
            if {$key in {status statusClass pool method recordSource bucketSeconds}} {
                set expected [expr {$key in {status bucketSeconds} ? "number" : "string"}]
                if {$type ne $expected || ($expected eq "string" && $value eq {})} {error "Invalid failed-traffic filter type/value"}
                dict set extras $key $value
            } elseif {$key in {selection mode}} {
                if {$type ne "string" || ($key eq "selection" && $value ni {ordered exhaustive}) || ($key eq "mode" && $value ni {summary evidence})} {error "Invalid access summary selection or mode"}
                dict set extras $key $value
            } elseif {$key eq "maxRecords"} {
                if {$type ne "number" || ![string is integer -strict $value] || $value<1 || $value>10000} {error "maxRecords must be 1..10000"}
                dict set extras $key $value
            } elseif {$key eq "pathLiteral"} {
                if {$type ne "string" || [string length [encoding convertto utf-8 $value]]<1
                    || [string length [encoding convertto utf-8 $value]]>256 || [regexp {[\x00-\x1f\x7f]} $value]} {error "pathLiteral must be 1..256 UTF-8 bytes without control characters"}
                dict set extras $key $value
            } elseif {$key eq "includeRotations"} {
                if {$type ne "boolean"} {error "includeRotations must be boolean"}
                dict set extras $key [expr {$value eq "true"}]
            } elseif {$key in {period timezone lastMinutes from to maxGroups}} {
                lappend base $key $type $value
            } else {error "Unknown access summary argument"}
        }
        return [::nsmcp::accessFailureOptions [dict merge [next [list [list {} object $base]]] $extras]]
    }
    :public method execute {context arguments} {
        return [${:service} start $context accessFileSummary [:options $arguments]]
    }
XQL Not present:
Generic, PostgreSQL, Oracle
[ hide source ] | [ make this the default ]
Show another procedure: