1808
This commit is contained in:
@@ -185,73 +185,84 @@ def extract_fields(obj: Dict[str, Any]):
|
|||||||
return product, mac, fw_active
|
return product, mac, fw_active
|
||||||
|
|
||||||
|
|
||||||
def extract_event_age_s(obj: Dict[str, Any]) -> Optional[int]:
|
def _parse_possible_event_epoch(value: Any) -> Optional[int]:
|
||||||
"""
|
|
||||||
Best-effort age of the registration event in seconds, derived from a timestamp
|
|
||||||
embedded in the payload if present. Returns None when no sane timestamp is found.
|
|
||||||
Surgical addition: no external calls, no broker queries.
|
|
||||||
"""
|
|
||||||
candidates = []
|
|
||||||
|
|
||||||
def _walk(x):
|
|
||||||
if isinstance(x, dict):
|
|
||||||
for k, v in x.items():
|
|
||||||
kl = str(k).strip().lower()
|
|
||||||
if kl in {"ts", "timestamp", "event_ts", "event_timestamp", "time", "created_at", "createdat", "published_at", "publishedat"}:
|
|
||||||
candidates.append(v)
|
|
||||||
_walk(v)
|
|
||||||
elif isinstance(x, list):
|
|
||||||
for item in x:
|
|
||||||
_walk(item)
|
|
||||||
|
|
||||||
def _to_epoch(v) -> Optional[int]:
|
|
||||||
try:
|
|
||||||
if isinstance(v, bool) or v is None:
|
|
||||||
return None
|
|
||||||
if isinstance(v, (int, float)):
|
|
||||||
n = float(v)
|
|
||||||
elif isinstance(v, str):
|
|
||||||
s = v.strip()
|
|
||||||
if not s:
|
|
||||||
return None
|
|
||||||
if s.endswith('Z'):
|
|
||||||
s = s[:-1] + '+00:00'
|
|
||||||
try:
|
|
||||||
return int(datetime.fromisoformat(s).timestamp())
|
|
||||||
except Exception:
|
|
||||||
n = float(s)
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
# milliseconds / microseconds / nanoseconds -> seconds
|
|
||||||
if n > 1e18:
|
|
||||||
n = n / 1e9
|
|
||||||
elif n > 1e15:
|
|
||||||
n = n / 1e6
|
|
||||||
elif n > 1e12:
|
|
||||||
n = n / 1e3
|
|
||||||
|
|
||||||
if 946684800 <= n <= 4102444800:
|
|
||||||
return int(n)
|
|
||||||
return None
|
|
||||||
except Exception:
|
|
||||||
return None
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
_walk(obj)
|
if value is None:
|
||||||
now_epoch = int(time.time())
|
return None
|
||||||
for raw in candidates:
|
if isinstance(value, bool):
|
||||||
epoch = _to_epoch(raw)
|
return None
|
||||||
if epoch is None:
|
if isinstance(value, (int, float)):
|
||||||
continue
|
v = float(value)
|
||||||
age = now_epoch - epoch
|
if v > 1e12:
|
||||||
if 0 <= age <= 86400 * 30:
|
v = v / 1000.0
|
||||||
return int(age)
|
if v > 0:
|
||||||
|
return int(v)
|
||||||
|
return None
|
||||||
|
if isinstance(value, str):
|
||||||
|
s = value.strip()
|
||||||
|
if not s:
|
||||||
|
return None
|
||||||
|
if s.isdigit():
|
||||||
|
v = float(s)
|
||||||
|
if v > 1e12:
|
||||||
|
v = v / 1000.0
|
||||||
|
if v > 0:
|
||||||
|
return int(v)
|
||||||
|
return None
|
||||||
|
s2 = s.replace("Z", "+00:00")
|
||||||
|
try:
|
||||||
|
return int(datetime.fromisoformat(s2).timestamp())
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
for fmt in ("%Y-%m-%d %H:%M:%S", "%Y-%m-%d %H:%M:%S%z", "%Y-%m-%dT%H:%M:%S", "%Y-%m-%dT%H:%M:%S%z"):
|
||||||
|
try:
|
||||||
|
dt = datetime.strptime(s, fmt)
|
||||||
|
if dt.tzinfo is None:
|
||||||
|
dt = dt.replace(tzinfo=timezone.utc)
|
||||||
|
return int(dt.timestamp())
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
except Exception:
|
except Exception:
|
||||||
return None
|
return None
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def extract_registration_age_s(obj: Dict[str, Any]) -> Optional[int]:
|
||||||
|
candidate_keys = {
|
||||||
|
"timestamp", "ts", "time", "event_time", "eventtime",
|
||||||
|
"event_ts", "eventtimestamp", "created_at", "createdat",
|
||||||
|
"published_at", "publishedat", "sent_at", "sentat",
|
||||||
|
"received_at", "receivedat",
|
||||||
|
}
|
||||||
|
|
||||||
|
def walk(node: Any) -> Optional[int]:
|
||||||
|
if isinstance(node, dict):
|
||||||
|
for k, v in node.items():
|
||||||
|
ks = str(k).strip().lower().replace("-", "_")
|
||||||
|
if ks in candidate_keys:
|
||||||
|
parsed = _parse_possible_event_epoch(v)
|
||||||
|
if parsed is not None:
|
||||||
|
return parsed
|
||||||
|
for v in node.values():
|
||||||
|
parsed = walk(v)
|
||||||
|
if parsed is not None:
|
||||||
|
return parsed
|
||||||
|
elif isinstance(node, list):
|
||||||
|
for item in node:
|
||||||
|
parsed = walk(item)
|
||||||
|
if parsed is not None:
|
||||||
|
return parsed
|
||||||
|
return None
|
||||||
|
|
||||||
|
epoch = walk(obj)
|
||||||
|
if epoch is None:
|
||||||
|
return None
|
||||||
|
age_s = int(time.time()) - int(epoch)
|
||||||
|
if age_s < 0:
|
||||||
|
return 0
|
||||||
|
return age_s
|
||||||
|
|
||||||
|
|
||||||
# =========================
|
# =========================
|
||||||
# NetBox lookup (urllib)
|
# NetBox lookup (urllib)
|
||||||
# =========================
|
# =========================
|
||||||
@@ -536,7 +547,7 @@ async def main():
|
|||||||
"netbox_ms": None,
|
"netbox_ms": None,
|
||||||
"total_ms": None,
|
"total_ms": None,
|
||||||
"nb_problems": None,
|
"nb_problems": None,
|
||||||
"event_age_s": None,
|
"reg_age_s": None,
|
||||||
}
|
}
|
||||||
|
|
||||||
# strict payload dedupe
|
# strict payload dedupe
|
||||||
@@ -557,7 +568,7 @@ async def main():
|
|||||||
text = payload.decode("utf-8", errors="replace")
|
text = payload.decode("utf-8", errors="replace")
|
||||||
obj = json.loads(text)
|
obj = json.loads(text)
|
||||||
product, mac, fw = extract_fields(obj)
|
product, mac, fw = extract_fields(obj)
|
||||||
event["event_age_s"] = extract_event_age_s(obj)
|
event["reg_age_s"] = extract_registration_age_s(obj)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -940,11 +951,9 @@ async def main():
|
|||||||
event["decision_reason"] = "mac not found in netbox"
|
event["decision_reason"] = "mac not found in netbox"
|
||||||
await log_event(event)
|
await log_event(event)
|
||||||
|
|
||||||
lag_suffix = ""
|
reg_age_s = event.get("reg_age_s")
|
||||||
if isinstance(event.get("event_age_s"), int):
|
reg_age_suffix = f" reg_age_s={reg_age_s}" if reg_age_s is not None else " reg_age_s=na"
|
||||||
lag_suffix = f" event_age_s={event['event_age_s']}"
|
line = f"nb_problems={nb_problems_snapshot} [{ts()}] product={product} mac={mac} fw={fw}{host_suffix}{action_suffix}{reg_age_suffix}"
|
||||||
|
|
||||||
line = f"nb_problems={nb_problems_snapshot} [{ts()}] product={product} mac={mac} fw={fw}{host_suffix}{action_suffix}{lag_suffix}"
|
|
||||||
if product == "fox100":
|
if product == "fox100":
|
||||||
line += f" netbox_ms={netbox_time_ms:.1f} total_ms={total_ms:.1f}"
|
line += f" netbox_ms={netbox_time_ms:.1f} total_ms={total_ms:.1f}"
|
||||||
if args.include_subject:
|
if args.include_subject:
|
||||||
|
|||||||
Reference in New Issue
Block a user