improve logging
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2026-02-11 11:24:27 +11:00
parent 34ac9287b4
commit f1be31781c
3 changed files with 110 additions and 22 deletions

View File

@@ -315,21 +315,59 @@ LIMIT 1
}
nextSnapshotRows.Close()
}
nextPresence := make(map[string]struct{})
// Build per-vCenter snapshot timelines from observed VM samples so deletion
// inference is only based on times where that vCenter actually reported data.
vcenterTimeSet := make(map[string]map[int64]struct{}, 8)
for _, v := range aggMap {
if v.key.Vcenter == "" {
continue
}
set := vcenterTimeSet[v.key.Vcenter]
if set == nil {
set = make(map[int64]struct{}, len(v.seen))
vcenterTimeSet[v.key.Vcenter] = set
}
for t := range v.seen {
if t > 0 {
set[t] = struct{}{}
}
}
}
vcenterSnapTimes := make(map[string][]int64, len(vcenterTimeSet))
for vcenter, set := range vcenterTimeSet {
times := make([]int64, 0, len(set))
for t := range set {
times = append(times, t)
}
sort.Slice(times, func(i, j int) bool { return times[i] < times[j] })
vcenterSnapTimes[vcenter] = times
}
nextPresenceByVcenter := make(map[string]map[string]struct{}, 8)
if nextSnapshotTable != "" && db.TableExists(ctx, dbConn, nextSnapshotTable) {
rows, err := querySnapshotRows(ctx, dbConn, nextSnapshotTable, []string{"VmId", "VmUuid", "Name"}, `"Vcenter" = ?`, c.Settings.Values.Settings.VcenterAddresses[0])
rows, err := querySnapshotRows(ctx, dbConn, nextSnapshotTable, []string{"Vcenter", "VmId", "VmUuid", "Name"}, "")
if err == nil {
for rows.Next() {
var vcenter string
var vmId, vmUuid, name sql.NullString
if err := rows.Scan(&vmId, &vmUuid, &name); err == nil {
if vmId.Valid {
nextPresence["id:"+vmId.String] = struct{}{}
if err := rows.Scan(&vcenter, &vmId, &vmUuid, &name); err == nil {
if strings.TrimSpace(vcenter) == "" {
continue
}
if vmUuid.Valid {
nextPresence["uuid:"+vmUuid.String] = struct{}{}
vcPresence := nextPresenceByVcenter[vcenter]
if vcPresence == nil {
vcPresence = make(map[string]struct{}, 1024)
nextPresenceByVcenter[vcenter] = vcPresence
}
if name.Valid {
nextPresence["name:"+name.String] = struct{}{}
if vmId.Valid && strings.TrimSpace(vmId.String) != "" {
vcPresence["id:"+strings.TrimSpace(vmId.String)] = struct{}{}
}
if vmUuid.Valid && strings.TrimSpace(vmUuid.String) != "" {
vcPresence["uuid:"+strings.TrimSpace(vmUuid.String)] = struct{}{}
}
if name.Valid && strings.TrimSpace(name.String) != "" {
vcPresence["name:"+strings.ToLower(strings.TrimSpace(name.String))] = struct{}{}
}
}
}
@@ -337,23 +375,24 @@ LIMIT 1
}
}
var maxSnap int64
if len(snapTimes) > 0 {
maxSnap = snapTimes[len(snapTimes)-1]
}
inferredDeletions := 0
for _, v := range aggMap {
if v.deletion != 0 {
continue
}
vcSnapTimes := vcenterSnapTimes[v.key.Vcenter]
// Deletion inference needs meaningful per-vCenter continuity.
if len(vcSnapTimes) < 3 {
continue
}
vcMaxSnap := vcSnapTimes[len(vcSnapTimes)-1]
// Infer deletion only after seeing at least two consecutive absent snapshots after lastSeen.
if maxSnap > 0 && len(v.seen) > 0 && v.lastSeen < maxSnap {
c.Logger.Debug("inferring deletion window", "vm_id", v.key.VmId, "vm_uuid", v.key.VmUuid, "name", v.key.Name, "last_seen", v.lastSeen, "snapshots", len(snapTimes))
if vcMaxSnap > 0 && len(v.seen) > 0 && v.lastSeen < vcMaxSnap {
c.Logger.Debug("inferring deletion window", "vcenter", v.key.Vcenter, "vm_id", v.key.VmId, "vm_uuid", v.key.VmUuid, "name", v.key.Name, "last_seen", v.lastSeen, "snapshots", len(vcSnapTimes))
}
consecutiveMisses := 0
firstMiss := int64(0)
for _, t := range snapTimes {
for _, t := range vcSnapTimes {
if t <= v.lastSeen {
continue
}
@@ -374,18 +413,19 @@ LIMIT 1
}
if v.deletion == 0 && firstMiss > 0 {
// Not enough consecutive misses within the day; try to use the first snapshot of the next day to confirm.
nextPresence := nextPresenceByVcenter[v.key.Vcenter]
if nextSnapshotTable != "" && len(nextPresence) > 0 {
_, presentByID := nextPresence["id:"+v.key.VmId]
_, presentByUUID := nextPresence["uuid:"+v.key.VmUuid]
_, presentByName := nextPresence["name:"+v.key.Name]
_, presentByID := nextPresence["id:"+strings.TrimSpace(v.key.VmId)]
_, presentByUUID := nextPresence["uuid:"+strings.TrimSpace(v.key.VmUuid)]
_, presentByName := nextPresence["name:"+strings.ToLower(strings.TrimSpace(v.key.Name))]
if !presentByID && !presentByUUID && !presentByName {
v.deletion = firstMiss
inferredDeletions++
c.Logger.Debug("cross-day deletion inferred from next snapshot", "vm_id", v.key.VmId, "vm_uuid", v.key.VmUuid, "name", v.key.Name, "deletion", firstMiss, "next_table", nextSnapshotTable)
c.Logger.Debug("cross-day deletion inferred from next snapshot", "vcenter", v.key.Vcenter, "vm_id", v.key.VmId, "vm_uuid", v.key.VmUuid, "name", v.key.Name, "deletion", firstMiss, "next_table", nextSnapshotTable)
}
}
if v.deletion == 0 {
c.Logger.Debug("pending deletion inference (insufficient consecutive misses)", "vm_id", v.key.VmId, "vm_uuid", v.key.VmUuid, "name", v.key.Name, "last_seen", v.lastSeen, "first_missing_snapshot", firstMiss)
c.Logger.Debug("pending deletion inference (insufficient consecutive misses)", "vcenter", v.key.Vcenter, "vm_id", v.key.VmId, "vm_uuid", v.key.VmUuid, "name", v.key.Name, "last_seen", v.lastSeen, "first_missing_snapshot", firstMiss)
}
}
}