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 access records. Use the existing start-time index only; do not scan raw logs or trigger ingestion or historical backfill. Peer addresses are never selected.

Parameters:
samples (required)
Up to three dictionaries with requestIdentifier and timestamp; optional system-log User-Agent fields take precedence over the cached agent.
redactor (required)
Redactor object applied before returning diagnostic evidence.
Returns:
Rooted JSON triples with sampled evidence and explicit missing and 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: