Class ::nsmcp::LogErrorSummaryTool (public)

 ::nx::Class ::nsmcp::LogErrorSummaryTool[i]

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

Testcases:
No testcase defined.
Source code:
    :property service:required
    :property {name log_error_summary}
    :property {permission diagnostics.logs.read}
    :property {description {Summarize system-log Error, Fatal and Bug records in a time window, with grouped counts, first/last occurrence, redacted examples and coverage. Prefer this for daily error summaries instead of paging all log_errors records. Defaults to today in UTC; period today/yesterday may use an explicit timezone, or use lastMinutes or from/to (exclusive end). Current log only; rotations are not examined. coverage.logBounds reports first/last file-order and earliest/latest observed epoch timestamps and offsets across all timestamped severities, not just matching errors. coverage.rotation distinguishes configured signal/filename settings from unknown schedule and last verified rotation time. Observed bounds never certify complete window coverage. Returns explicit severityTotals independently of maxGroups. coverage.unrecognizedRecords counts unrecognized system-log entries; coverage.unrecognizedExamples provides up to five redacted examples with byte offsets. Recognizes stderr mutex traces and short startup entries separately via coverage.mutexTraceRecords, shortLogRecords and untimestampedExamples. Recognizes PostgreSQL diagnostics with grouped DETAIL/HINT/CONTEXT via postgresRecords and postgresExamples. Neighboring timestamps are explicitly labeled inferred-neighbors; they are contextual bounds, not guaranteed event times. These diagnostic counters cover the scanned file; inferred times never enter window totals. Mutex traces are not errors; untimestamped Error/Fatal/Bug entries are reported as unknownTimeErrors rather than included in window totals. Scans the current file in resumable chunks with fixed bounds; running jobs report progress.examinedBytes and progress.sourceBytes. Runs asynchronously: poll log_results with jobHandle until complete; the completed result is the summary and has no record pages. Grouping is heuristic and bounded; report ungroupedRecords and coverage limitations.}}
    :property {inputSchema {{} object {type string object properties object {
        period object {type string string enum array {0 string today 1 string yesterday}}
        timezone object {type string string}
        lastMinutes object {type string integer minimum number 1 maximum number 10080}
        from object {type string integer minimum number 0}
        to object {type string integer minimum number 1}
        maxGroups object {type string integer minimum number 1 maximum number 50}
    } additionalProperties boolean false}}}

    :method options {arguments} {
        if {[lindex $arguments 1] ne "object"} {error "Expected an arguments object"}
        set values {timezone UTC maxGroups 20}
        set seen {}
        foreach {key type value} [lindex $arguments 2] {
            if {$key ni {period timezone lastMinutes from to maxGroups} || $key in $seen} {error "Unknown or duplicate summary argument"}
            lappend seen $key
            set expected [expr {$key in {period timezone} ? "string" : "number"}]
            if {$type ne $expected || ($type eq "number" && ![string is entier -strict $value])} {error "Invalid summary argument type"}
            dict set values $key $value
        }
        set timezone [dict get $values timezone]
        if {[string length $timezone]>128 || ![regexp {^[A-Za-z][A-Za-z0-9_+-]*(/[A-Za-z][A-Za-z0-9_+-]*)*$} $timezone] || [catch {clock format [clock seconds] -timezone $timezone}]} {error "Invalid timezone"}
        set selectors [expr {[dict exists $values period]+[dict exists $values lastMinutes]+([dict exists $values from] || [dict exists $values to])}]
        if {$selectors>1} {error "Use one time selector: period, lastMinutes or from/to"}
        set now [clock seconds]
        if {[dict exists $values from] || [dict exists $values to]} {
            if {![dict exists $values from] || ![dict exists $values to]} {error "Supply both from and to"}
        } elseif {[dict exists $values lastMinutes]} {
            set minutes [dict get $values lastMinutes]
            if {$minutes<1 || $minutes>10080} {error "lastMinutes must be 1..10080"}
            dict set values from [expr {$now-60*$minutes}]
            dict set values to $now
        } else {
            set period [expr {[dict exists $values period] ? [dict get $values period] : "today"}]
            if {$period ni {today yesterday}} {error "Invalid period"}
            set midnight [clock scan [clock format $now -timezone $timezone -format %Y-%m-%d] -timezone $timezone -format %Y-%m-%d]
            dict set values from [expr {$period eq "today" ? $midnight : [clock add $midnight -1 day -timezone $timezone]}]
            dict set values to [expr {$period eq "today" ? $now : $midnight}]
        }
        if {[dict get $values from]<0 || [dict get $values from]>=[dict get $values to]} {error "Expected 0 <= from < to"}
        if {[dict get $values maxGroups]<1 || [dict get $values maxGroups]>50} {error "maxGroups must be 1..50"}
        return $values
    }
    :public method validate {arguments} {
        if {[catch {:options $arguments} message]} {return -code error -errorcode {NSMCP RPC -32602} $message}
    }
    :public method execute {context arguments} {
        return [${:service} start $context errorSummary [:options $arguments]]
    }
XQL Not present:
Generic, PostgreSQL, Oracle
[ hide source ] | [ make this the default ]
Show another procedure: