nsmcp::AccessAnalytics method correlateWarnings (public)

 <instance of nsmcp::AccessAnalytics[i]> correlateWarnings samples \
    redactor

Defined in /usr/local/ns/tcl/nsmcp/access-analytics.tcl

Correlate bounded warning examples with retained cache rows only. The existing start-time index bounds lookups; no raw log is scanned and no ingestion/backfill is triggered. Addresses are never selected.

Parameters:
samples (required)
Up to three dictionaries with requestIdentifier and timestamp; optional userAgent and userAgentMayBeTruncated from system-log diagnostics take precedence over cached User-Agent.
redactor (required)
Redactor applied to returned text fields.
Returns:
Rooted JSON triples with sampled evidence and explicit missing/ambiguous counts.

Testcases:
No testcase defined.
Source code:
if {[llength $samples] > 3} {error "Too many warning correlation samples"}
set fields {}; set matched 0; set missing 0; set ambiguous 0; set i 0
set db [${:database} connect]
try {
    foreach sample $samples {
        set request_id [dict get $sample requestIdentifier]
        set at [dict get $sample timestamp]
        if {![::nsmcp::logRecordParser validConnectionIdentifier $request_id]
            || ![string match "-conn:[ns_info server]:*" $request_id]
            || ![string is double -strict $at]} {incr missing; continue}
        set lower [expr {$at-60}]; set upper [expr {$at+1}]
        set rows [$db execute {SELECT request_id,start,path,pool,method,status,authenticationState,userAgent
            FROM nsmcp_access_requests WHERE start >= $lower AND start <= $upper
            AND request_id=$request_id LIMIT 2}]
        if {[llength $rows] == 0} {incr missing; continue}
        if {[llength $rows] > 1} {incr ambiguous; continue}
        set row [lindex $rows 0]; set item {}
        set uaSource access-cache
        set authSource access-cache
        if {[dict exists $sample authenticationState] && [dict get $sample authenticationState] in {anonymous authenticated}} {
            dict set row authenticationState [dict get $sample authenticationState]
            set authSource system-log
        }
        set uaTruncated [expr {[string length [dict get $row userAgent]] >= 1024}]
        if {[dict exists $sample userAgent]} {
            dict set row userAgent [dict get $sample userAgent]
            set uaSource system-log
            set uaTruncated [dict get $sample userAgentMayBeTruncated]
        }
        foreach key {path pool method authenticationState userAgent} {
            lappend item $key string [$redactor message [dict get $row $key]]
        }
        lappend item requestIdentifier string $request_id start number [dict get $row start]  status number [dict get $row status] warningTimestamp number $at authenticationSource string $authSource  userAgentAvailable boolean [expr {[dict get $row userAgent] ne ""}]  userAgentSource string $uaSource userAgentMayBeTruncated boolean $uaTruncated
        lappend fields $i object $item; incr i; incr matched
    }
} finally {$db close}
return [list {} object [list available boolean true scope string sampled-warning-requests  requested number [llength $samples] matched number $matched missing number $missing ambiguous number $ambiguous  records array $fields limitations string {Bounded examples, not aggregate bot attribution. Exact connection identifier and start time within 60 seconds before to 1 second after the warning are required. Cache lag, eviction, long requests, legacy rows without User-Agent, and absent identifiers can prevent matches. No raw access-log scan or cache refresh was performed. Multiple candidates are not attributed. Pool and User-Agent alone do not prove bot or human identity. No peer addresses are returned.}]]
XQL Not present:
Generic, PostgreSQL, Oracle
[ hide source ] | [ make this the default ]
Show another procedure: