Class ::nsmcp::AccessSummaryTool (public)

 ::nx::Class ::nsmcp::AccessSummaryTool[i]

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

Testcases:
No testcase defined.
Source code:
    :property service:required
    :property analytics:required
    :property {name access_summary}
    :property {permission diagnostics.logs.read}
    :property {description {Query the continuously populated shared access store; this reader does not parse or import logs. Live lag, historical backfill, record-age retention and shorter peer-address retention are explicit. Legacy configurations retain their previous cache behavior. Poll log_results with jobHandle. Defaults to the last 60 completed minutes. Use lastMinutes or period previous-hour for relative intervals, or reuse windowHandle to freeze bounds across comparisons. Time selectors are mutually exclusive; explicit from/to remain supported. Counts use request start times when available. Sub-minute bucketSeconds (1, 5, 10, 15, 30) supports peak analysis, with at most 3600 buckets. Sub-minute windows round outwards to bucket boundaries; other windows round to minutes. Counts are observed retained-cache traffic, not certified full-log totals; coverage reports recent-scan progress, historical backfill, completion-order assumptions, and possible rotation gaps. Reports authenticationStates aggregates derived from the logged user field (0 or - anonymous, other nonempty identities authenticated; old cache rows unknown). Does not disclose user identities. Supports authenticationState, exact path, status and pool filters and timing breakdowns by status. Coverage separates live-tail lag, historical backfill, cumulative parsing failures and outward bucket rounding; do not treat the rounded future minute as ingestion lag. Optional windowSeconds finds the maximum requests from one logged peer in a rolling inclusive window within the selected period; default 600 seconds. Peer addresses are retained internally; peer filtering and disclosure require diagnostics.logs.peers.read. Existing cache rows may lack peers; inspect unknownPeerCount, observedPeerCountsComplete, peerCountsComplete and peerCountsIncompleteReasons. Observed peer fields can be complete while the requested log window is incomplete; peerCountsIncompleteReasons explains both. Top paths omit queries and may be incomplete when cardinality limits are reached.}}
    :property {inputSchema {
        {
            "type": "object",
            "properties": {
                "lastMinutes": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 1440,
                    "description": "Trailing minutes ending at the last completed minute; default 60"
                },
                "period": {
                    "type": "string",
                    "enum": [
                        "previous-hour"
                    ],
                    "description": "Previous complete UTC clock hour"
                },
                "windowHandle": {
                    "type": "string",
                    "description": "Reuse bounds returned by an earlier summary; owned by this principal and server"
                },
                "from": {
                    "type": "integer",
                    "description": "Unix epoch seconds; explicit interval start"
                },
                "to": {
                    "type": "integer",
                    "description": "Unix epoch seconds; explicit interval end"
                },
                "authenticationState": {
                    "type": "string",
                    "enum": [
                        "anonymous",
                        "authenticated",
                        "unknown"
                    ]
                },
                "path": {
                    "type": "string",
                    "description": "Exact queryless path"
                },
                "peer": {
                    "type": "string",
                    "description": "Exact logged IP address; requires peer permission"
                },
                "windowSeconds": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 3600,
                    "description": "Rolling peer burst duration, defaults to 600; inclusive endpoints. Use 0 to skip peer-burst calculation for traffic-only analysis."
                },
                "includePeerAddresses": {
                    "type": "boolean",
                    "description": "Disclose the burst peer; requires peer permission"
                },
                "pool": {
                    "type": "string",
                    "description": "Exact connection pool"
                },
                "status": {
                    "type": "integer",
                    "minimum": 100,
                    "maximum": 599,
                    "description": "HTTP status"
                },
                "bucketSeconds": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 3600,
                    "description": "1, 5, 10, 15, 30, or a multiple of 60; at most 3600 buckets"
                }
            },
            "additionalProperties": false
        }
    }}

    :public method options {arguments} {
        #
        # Decode and validate access-summary tool options.
        #
        # Convert the rooted JSON arguments to the supported query and pagination
        # settings.
        #
        # @param arguments Rooted ns_json typed triples for the tool's JSON argument
        #        object.
        #
        # @return A Tcl dictionary of access-summary options.
        #

        set options {windowSeconds 600}
        if {[lindex $arguments 1] ne "object"} {
            error "Expected arguments object"
        }
        foreach {key type value} [lindex $arguments 2] {
            if {$key eq "includePeerAddresses"} {
                if {$type ne "boolean"} {
                    error "Expected boolean includePeerAddresses"
                }
            } elseif {$key in {path pool peer authenticationState period windowHandle}} {
                if {$type ne "string"} {
                    error "Expected string path or pool"
                }
            } elseif {$key ni {from to bucketSeconds status windowSeconds lastMinutes} || $type ne "number" || ![string is entier -strict $value]} {
                error "Expected integer times/status or string path/pool"
            }
            dict set options $key $value
        }
        set selectors 0
        foreach key {lastMinutes period windowHandle} {
            if {[dict exists $options $key]} {
                incr selectors
            }
        }
        set explicit [expr {[dict exists $options from] || [dict exists $options to]}]
        if {$selectors>1 || ($selectors && $explicit)} {
            error "Use one of lastMinutes, period, windowHandle, or explicit from/to"
        }
        if {[dict exists $options windowHandle]} {
            set handle [dict get $options windowHandle]
            if {![regexp {^[0-9a-f]{64}$} $handle]} {
                error "Invalid windowHandle"
            }
            dict unset options windowHandle
            set checked [${:analytics} validateWindow $options]
            dict unset checked from
            dict unset checked to
            dict set checked windowHandle $handle
            return $checked
        }
        set now [clock seconds]
        if {[dict exists $options period]} {
            if {[dict get $options period] ne "previous-hour"} {
                error "period must be previous-hour"
            }
            dict unset options period
            set end [expr {($now/3600)*3600}]
            dict set options from [expr {$end-3600}]
            dict set options to $end
        } elseif {[dict exists $options lastMinutes] || !$explicit} {
            set minutes 60
            if {[dict exists $options lastMinutes]} {
                set minutes [dict get $options lastMinutes]
                dict unset options lastMinutes
            }
            if {$minutes<1 || $minutes>1440} {
                error "lastMinutes must be between 1 and 1440"
            }
            set end [expr {($now/60)*60}]
            dict set options from [expr {$end-$minutes*60}]
            dict set options to $end
        }
        return [${:analytics} validateWindow $options]
    }

    :public method validate {arguments} {
        #
        # Validate access-summary arguments.
        #
        # Decode the rooted JSON argument object and enforce this tool's option,
        # range and combination constraints.
        #
        # @param arguments Rooted ns_json typed triples for the tool's JSON argument
        #        object.
        #
        # @return An empty result on success; invalid input raises RPC error -32602.
        #

        if {[catch {
            :options $arguments
        } message]} {
            return -code error -errorcode {NSMCP RPC -32602} $message
        }
    }

    :public method execute {context arguments} {
        #
        # Start an owned access-log summary operation.
        #
        # Resolve retained window handles through the service before queuing the
        # validated summary options.
        #
        # @param context Authenticated request context carrying the principal,
        #        grants and selected server.
        # @param arguments Rooted ns_json typed triples for the tool's JSON argument
        #        object.
        #
        # @return A rooted JSON tool-result object, including availability or job
        #         metadata as appropriate.
        #

        set options [:options $arguments]
        if {[dict exists $options windowHandle]} {
            set bounds [${:service} resolveWindow $context [dict get $options windowHandle]]
            dict unset options windowHandle
            set options [${:analytics} validateWindow [dict merge $options $bounds]]
        }
        return [${:service} start $context accessSummary $options]
    }
XQL Not present:
Generic, PostgreSQL, Oracle
[ hide source ] | [ make this the default ]
Show another procedure: