fix: daily report без локального Telegram при fallback SAC (2.1.9-SAC)

Аналог ssh-monitor: report.daily.* только SAC/spool, timeout 45s,
spool flush приоритет отчётам (50 файлов/цикл).

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-06 12:00:36 +10:00
parent f2bcc6c7df
commit f033d5bd87
4 changed files with 84 additions and 16 deletions
+5 -3
View File
@@ -90,7 +90,7 @@ $script:SkipLogDetailLimit = 15
# строки ниже, если правки «мелкие» и вы не хотите менять отображаемую версию в логах).
# Рекомендация: при значимых релизах меняйте и $ScriptVersion, и version.txt одинаково; при только
# исправлениях на шаре — достаточно поднять patch в version.txt (например 1.3.0.1).
$ScriptVersion = "2.1.8-SAC"
$ScriptVersion = "2.1.9-SAC"
# Логи (все под InstallRoot)
$LogFile = Join-Path $script:InstallRoot "Logs\login_monitor.log"
@@ -258,7 +258,9 @@ $SacUrl = ''
$SacApiKey = ''
$SacSpoolDir = ''
$SacAgentIdFile = ''
$SacTimeoutSec = 12
$SacTimeoutSec = 45
$SacSpoolFlushMaxFiles = 50
$SacSpoolMaxAgeHours = 72
$SacTlsSkipVerify = $false
$SacFallbackFailures = 5
@@ -5040,7 +5042,7 @@ function Start-LoginMonitor {
$nextReportCheck = Check-AndSendDailyReport
}
if ($script:SacClientLoaded) {
Invoke-SacFlushSpool -MaxFiles 20 | Out-Null
Invoke-SacFlushSpool | Out-Null
if ((Get-SacNormalizedMode) -ne 'off' -and $now -ge $script:NextSacCommandPollTime) {
Invoke-SacProcessPendingCommands | Out-Null
$script:NextSacCommandPollTime = $now.AddSeconds($SacCommandPollIntervalSec)
+75 -11
View File
@@ -430,7 +430,7 @@ function Test-SacHealth {
$base = Get-SacBaseUrl
if ([string]::IsNullOrWhiteSpace($base)) { return $false }
$timeout = if ($SacTimeoutSec) { [int]$SacTimeoutSec } else { 12 }
$timeout = Get-SacTimeoutSecResolved
try {
Invoke-SacTlsPrep
$resp = Invoke-WebRequest -Uri "$base/health" -Method Get -UseBasicParsing -TimeoutSec $timeout
@@ -691,7 +691,7 @@ function Invoke-SacPostPayload {
if ($jsonText -match '"type"\s*:\s*"([^"]+)"') {
$eventType = $Matches[1]
}
$timeout = if ($SacTimeoutSec) { [int]$SacTimeoutSec } else { 12 }
$timeout = Get-SacTimeoutSecResolved
$spoolOnFailure = $true
$bodyBytes = $null
@@ -811,6 +811,31 @@ function Test-SacHeartbeatOnlyEventType {
return ($EventType -eq 'agent.heartbeat')
}
function Test-SacDailyReportEventType {
param([string]$EventType)
return ($EventType -in @('report.daily.rdp', 'report.daily.ssh'))
}
function Get-SacTimeoutSecResolved {
if ($SacTimeoutSec) {
$n = 0
if ([int]::TryParse([string]$SacTimeoutSec, [ref]$n) -and $n -gt 0) {
return $n
}
}
return 45
}
function Get-SacSpoolFlushMaxFilesResolved {
if (Get-Variable -Name SacSpoolFlushMaxFiles -ErrorAction SilentlyContinue) {
$n = 0
if ([int]::TryParse([string]$SacSpoolFlushMaxFiles, [ref]$n) -and $n -gt 0) {
return $n
}
}
return 50
}
function Merge-SacNotifyDetails {
param(
[hashtable]$Details = $null,
@@ -883,6 +908,20 @@ function Send-NotifyOrSac {
return (Send-SacEvent @sacEventArgs)
}
# Суточный отчёт — только SAC/spool; при сбое ingest не дублировать в локальный Telegram.
if (Test-SacDailyReportEventType -EventType $EventType) {
if ($mode -eq 'off') {
return $false
}
$merged = Merge-SacNotifyDetails -Details $Details -TelegramVia 'sac'
$sacEventArgs = Get-SacEventInvokeArgs -EventType $EventType -Severity $Severity -Title $Title -Summary $Summary -Details $merged -OccurredAt $OccurredAt
if (Send-SacEvent @sacEventArgs) {
return $true
}
Write-SacLog 'WARN: daily report не принят SAC — остаётся в spool (локальный Telegram пропущен)'
return $false
}
switch ($mode) {
'off' {
return (Send-SacLocalChannels -TelegramMessage $TelegramMessage -EmailSubject $EmailSubject)
@@ -914,7 +953,11 @@ function Send-NotifyOrSac {
}
function Invoke-SacFlushSpool {
param([int]$MaxFiles = 20)
param([int]$MaxFiles = 0)
if ($MaxFiles -le 0) {
$MaxFiles = Get-SacSpoolFlushMaxFilesResolved
}
$mode = Get-SacNormalizedMode
if ($mode -eq 'off') { return }
@@ -923,11 +966,32 @@ function Invoke-SacFlushSpool {
$dir = Get-SacSpoolDirResolved
if (-not (Test-Path -LiteralPath $dir)) { return }
# Сначала свежие события (daily report); битые записи уходят в rejected и не блокируют очередь.
$files = @(Get-ChildItem -LiteralPath $dir -Filter '*.json' -File -ErrorAction SilentlyContinue |
Sort-Object LastWriteTime -Descending)
$count = 0
$files = @(Get-ChildItem -LiteralPath $dir -Filter '*.json' -File -ErrorAction SilentlyContinue)
$daily = @()
$other = @()
foreach ($f in $files) {
$eventType = ''
try {
$raw = Read-SacSpoolFileText -Path $f.FullName
if (-not [string]::IsNullOrWhiteSpace($raw)) {
$obj = $raw | ConvertFrom-Json -ErrorAction Stop
if ($null -ne $obj.type) { $eventType = [string]$obj.type }
}
} catch {
$eventType = ''
}
if (Test-SacDailyReportEventType -EventType $eventType) {
$daily += $f
} else {
$other += $f
}
}
$ordered = @(
@($daily | Sort-Object LastWriteTime)
@($other | Sort-Object LastWriteTime)
)
$count = 0
foreach ($f in $ordered) {
$count++
if ($count -gt $MaxFiles) { break }
try {
@@ -964,7 +1028,7 @@ function Get-SacAgentCommandResultUrl {
function Invoke-SacHttpGet {
param(
[Parameter(Mandatory = $true)][string]$Uri,
[int]$TimeoutSec = 12
[int]$TimeoutSec = 45
)
Invoke-SacTlsPrep
try {
@@ -990,7 +1054,7 @@ function Invoke-SacHttpPostJson {
param(
[Parameter(Mandatory = $true)][string]$Uri,
[Parameter(Mandatory = $true)][string]$JsonBody,
[int]$TimeoutSec = 12
[int]$TimeoutSec = 45
)
Invoke-SacTlsPrep
$bytes = Get-SacUtf8Bytes -Text $JsonBody
@@ -1119,7 +1183,7 @@ function Submit-SacAgentCommandResult {
stdout = $Stdout
stderr = $Stderr
} | ConvertTo-Json -Compress
$timeout = if ($SacTimeoutSec) { [int]$SacTimeoutSec } else { 12 }
$timeout = Get-SacTimeoutSecResolved
$resp = Invoke-SacHttpPostJson -Uri $url -JsonBody $body -TimeoutSec $timeout
return ($resp.StatusCode -in 200, 201)
}
@@ -1132,7 +1196,7 @@ function Invoke-SacProcessPendingCommands {
if ([string]::IsNullOrWhiteSpace($pollUrl)) { return 0 }
$agentId = Get-SacAgentInstanceId
$timeout = if ($SacTimeoutSec) { [int]$SacTimeoutSec } else { 12 }
$timeout = Get-SacTimeoutSecResolved
$uri = "${pollUrl}?agent_instance_id=$([uri]::EscapeDataString($agentId))"
$get = Invoke-SacHttpGet -Uri $uri -TimeoutSec $timeout
if ($get.StatusCode -ne 200) {
+3 -1
View File
@@ -37,7 +37,9 @@ $UseSAC = 'fallback'
$SacUrl = 'https://sac.kalinamall.ru'
$SacApiKey = 'sac_UkOsAT3UWiQS54KK5OJPBDCSucysQDrKFju28wmYiz8'
$SacSpoolDir = 'C:\ProgramData\RDP-login-monitor\sac-spool'
# $SacTimeoutSec = 12
$SacTimeoutSec = 45
$SacSpoolFlushMaxFiles = 50
$SacSpoolMaxAgeHours = 72
# $SacTlsSkipVerify = $false
# $SacFallbackFailures = 5
# $false = не слать report.daily.rdp с агента (суточный отчёт только из SAC)
+1 -1
View File
@@ -1 +1 @@
2.1.8-SAC
2.1.9-SAC