nsmcp::AccessAnalytics method correlateInvalidRequests (public)
<instance of nsmcp::AccessAnalytics> correlateInvalidRequests \ samples redactor
Defined in /usr/local/ns/tcl/nsmcp/log-peer-context.tcl
Return bounded all-status context for sampled invalid-request warnings. Query retained unified records by private peer digest and a short time range. Do not import logs, expose peer keys, or infer TCP connection identity.
- Parameters:
- samples (required)
- At most twelve dictionaries with timestamp, offset and peerKey.
- redactor (required)
- Output redactor for paths and self-reported User-Agents.
- Returns:
- JSON triples with sampled sequences, redirect counts and limits.
- Testcases:
- No testcase defined.
Source code: if {[llength $samples]>12} {error "too many invalid-request warning samples"} foreach sample $samples { if {![dict exists $sample peerKey] || ![regexp {^[0-9a-f]{64}$} [dict get $sample peerKey]] || ![dict exists $sample timestamp] || ![string is double -strict [dict get $sample timestamp]] || ![dict exists $sample offset] || ![string is wideinteger -strict [dict get $sample offset]]} { error "invalid invalid-request warning sample" } set timestamp [dict get $sample timestamp] if {[catch {expr {$timestamp>=0 && $timestamp<[clock seconds]+3600}} valid] || !$valid} { error "invalid invalid-request warning timestamp" } } if {![info exists :settings] || ![nsf::object::exists ${:database}] || ![${:database} info has type ::nsmcp::UnifiedAccessDatabase]} { return [list {} object [list available boolean false reason string continuous-access-store-required]] } set began [clock milliseconds] set store [:accessRecordReaderOpen ${:settings}] try { set db [$store session] $db execute BEGIN set floor [expr {max([$store stateGet retentionFloor 0], wide(floor(([clock seconds]-[dict get ${:settings} retention])/60.0))*60)}] set entries {} set index 0 set matched 0 set redirects 0 set redirects302 0 set limited 0 foreach sample $samples { set at [dict get $sample timestamp] set lo [expr {max($floor,$at-30)}] set hi [expr {$at+6}] set peerKey [dict get $sample peerKey] set before [$db execute [::nsmcp::invalidRequestContextSQL $peerKey before]] set after [$db execute [::nsmcp::invalidRequestContextSQL $peerKey after]] set truncated [expr {[llength $before]>16 || [llength $after]>5}] incr limited $truncated set before [lrange $before 0 15] set after [lrange $after 0 4] set records {} set n 0 set hasRedirect false set has302 false foreach row [concat [lreverse $before] $after] { set time [dict get $row t] set relation [expr {$time<$at ? "before" : ($time<$at+1 ? "same-second" : "after")}] set status [dict get $row status] if {$relation eq "before" && $status in {300 301 302 303 307 308}} { set hasRedirect true if {$status==302} {set has302 true} } set fields [list requestStart number $time requestStartOffsetSeconds number [expr {$time-$at}] relation string $relation status number $status] foreach key {path method pool source driver userAgent} { set text [dict get $row $key] if {$key eq "path"} {set text [lindex [split $text ?] 0]} lappend fields $key string [$redactor message $text] } lappend fields userAgentMayBeTruncated boolean [expr {[dict get $row clipped] || [string length [dict get $row userAgent]]>=1024}] lappend records $n object $fields incr n } if {$n>0} {incr matched} if {$hasRedirect} {incr redirects} if {$has302} {incr redirects302} lappend entries $index object [list warningTimestamp number $at warningOffset number [dict get $sample offset] records array $records returnedRecords number $n recordsTruncated boolean $truncated precedingRedirectObserved boolean $hasRedirect preceding302Observed boolean $has302 retentionClipped boolean [expr {$lo>$at-30}]] incr index } $db execute COMMIT return [list {} object [list available boolean true scope string sampled-warning-same-peer-context beforeSeconds number 30 afterSeconds number 5 warningTimestampResolutionSeconds number 1 beforeRecordLimit number 16 afterRecordLimit number 5 matchedWarnings number $matched missingWarnings number [expr {[llength $samples]-$matched}] warningsWithPrecedingRedirect number $redirects warningsWithPreceding302 number $redirects302 recordLimitedWarnings number $limited sequences array $entries queryMilliseconds number [expr {max(0,[clock milliseconds]-$began)}] limitations string {Same logged peer and nearby request start times are contextual association, not proof of one TCP connection, client identity, redirect following or causation. Multiple clients can share an address. Warning times have one-second resolution: requests in that second are labeled same-second, not preceding. A preceding start does not establish response completion before the warning. No redirect Location is available. Includes all statuses, not just 400. Only committed, active-source records within retention are queried; ingestion lag, missing imports and retention can hide context. Missing context is unknown, not proof of probing. Counts describe sampled warnings and bounded returned records, not population rates. No peer addresses or peer digests are returned.}]] } finally { $store close }XQL Not present: Generic, PostgreSQL, Oracle
![[i]](/resources/acs-subsite/ZoomIn16.gif)