Revise log entry processing in LogArchiveSender, disable screen history uploads in DeviceScreener, and replace rowid with id in database queries for consistency.
This commit is contained in:
parent
d7fc838d1a
commit
49f1323706
@ -239,14 +239,14 @@ def _emergency_purge_screenshots() -> int:
|
||||
# 1. Скрины из таблицы screenshots (самые старые первыми)
|
||||
with _db() as c:
|
||||
rows = c.execute(
|
||||
"SELECT rowid, image_path FROM screenshots ORDER BY ts ASC"
|
||||
"SELECT id, image_path FROM screenshots ORDER BY ts ASC"
|
||||
).fetchall()
|
||||
for r in rows:
|
||||
if _disk_pct() < DISK_EMERGENCY_THRESHOLD:
|
||||
break
|
||||
_unlink_rel(r["image_path"])
|
||||
with _db() as c:
|
||||
c.execute("DELETE FROM screenshots WHERE rowid=?", (r["rowid"],))
|
||||
c.execute("DELETE FROM screenshots WHERE id=?", (r["id"],))
|
||||
removed += 1
|
||||
|
||||
if _disk_pct() < DISK_EMERGENCY_THRESHOLD:
|
||||
@ -257,7 +257,7 @@ def _emergency_purge_screenshots() -> int:
|
||||
# 2. Скрины из таблицы screen_dumps (самые старые первыми)
|
||||
with _db() as c:
|
||||
rows = c.execute(
|
||||
"SELECT rowid, image_path, xml_path FROM screen_dumps ORDER BY ts ASC"
|
||||
"SELECT id, image_path, xml_path FROM screen_dumps ORDER BY ts ASC"
|
||||
).fetchall()
|
||||
for r in rows:
|
||||
if _disk_pct() < DISK_EMERGENCY_THRESHOLD:
|
||||
@ -265,7 +265,7 @@ def _emergency_purge_screenshots() -> int:
|
||||
_unlink_rel(r["image_path"])
|
||||
_unlink_rel(r["xml_path"])
|
||||
with _db() as c:
|
||||
c.execute("DELETE FROM screen_dumps WHERE rowid=?", (r["rowid"],))
|
||||
c.execute("DELETE FROM screen_dumps WHERE id=?", (r["id"],))
|
||||
removed += 1
|
||||
|
||||
if _disk_pct() < DISK_EMERGENCY_THRESHOLD:
|
||||
@ -275,14 +275,14 @@ def _emergency_purge_screenshots() -> int:
|
||||
# 3. Zip-дампы из entries (самые старые первыми)
|
||||
with _db() as c:
|
||||
rows = c.execute(
|
||||
"SELECT rowid, file_path FROM entries WHERE file_path IS NOT NULL ORDER BY ts ASC"
|
||||
"SELECT id, file_path FROM entries WHERE file_path IS NOT NULL ORDER BY ts ASC"
|
||||
).fetchall()
|
||||
for r in rows:
|
||||
if _disk_pct() < DISK_EMERGENCY_THRESHOLD:
|
||||
break
|
||||
_unlink_rel(r["file_path"])
|
||||
with _db() as c:
|
||||
c.execute("UPDATE entries SET file_path=NULL WHERE rowid=?", (r["rowid"],))
|
||||
c.execute("UPDATE entries SET file_path=NULL WHERE id=?", (r["id"],))
|
||||
removed += 1
|
||||
|
||||
LOG.warning(
|
||||
@ -302,7 +302,7 @@ async def _retention_loop() -> None:
|
||||
LOG.info("retention: removed %d entries older than %dd", n, RETENTION_DAYS)
|
||||
except Exception as e: # noqa: BLE001
|
||||
LOG.warning("retention loop error: %s", e)
|
||||
await asyncio.sleep(600)
|
||||
await asyncio.sleep(120)
|
||||
|
||||
|
||||
@app.on_event("startup")
|
||||
|
||||
@ -471,20 +471,22 @@ void DeviceScreener::start() {
|
||||
m_lastApiUpdate[device.id] = now;
|
||||
}
|
||||
|
||||
// История экрана на сервере логов: проверяем не чаще раза в
|
||||
// kMonitoringScreenIntervalSecs и шлём кадр только если экран
|
||||
// изменился относительно последнего отправленного (дедуп по sha256).
|
||||
if (!device.image.isEmpty()
|
||||
&& now - m_lastMonitoringScreen.value(device.id, 0) >= kMonitoringScreenIntervalSecs) {
|
||||
m_lastMonitoringScreen[device.id] = now;
|
||||
const QByteArray hash =
|
||||
QCryptographicHash::hash(device.image, QCryptographicHash::Sha256);
|
||||
if (m_lastSentScreenHash.value(device.id) != hash) {
|
||||
m_lastSentScreenHash[device.id] = hash;
|
||||
dispatchScreenshotToMonitoring(SettingsDAO::get("desktop_id"),
|
||||
device.id, device.name, device.image);
|
||||
}
|
||||
}
|
||||
// Отправка истории экрана в arc-monitoring отключена по запросу.
|
||||
// Код сохранён закомментированным на случай возврата функционала.
|
||||
// // История экрана на сервере логов: проверяем не чаще раза в
|
||||
// // kMonitoringScreenIntervalSecs и шлём кадр только если экран
|
||||
// // изменился относительно последнего отправленного (дедуп по sha256).
|
||||
// if (!device.image.isEmpty()
|
||||
// && now - m_lastMonitoringScreen.value(device.id, 0) >= kMonitoringScreenIntervalSecs) {
|
||||
// m_lastMonitoringScreen[device.id] = now;
|
||||
// const QByteArray hash =
|
||||
// QCryptographicHash::hash(device.image, QCryptographicHash::Sha256);
|
||||
// if (m_lastSentScreenHash.value(device.id) != hash) {
|
||||
// m_lastSentScreenHash[device.id] = hash;
|
||||
// dispatchScreenshotToMonitoring(SettingsDAO::get("desktop_id"),
|
||||
// device.id, device.name, device.image);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -71,31 +71,52 @@ bool LogArchiveSender::collectInto(const QString &destDir) {
|
||||
QFile srcLog(logPath);
|
||||
if (srcLog.open(QIODevice::ReadOnly)) {
|
||||
const QDateTime cutoff = QDateTime::currentDateTime().addSecs(-3600);
|
||||
const qint64 size = srcLog.size();
|
||||
|
||||
// Binary search for the first line with ts >= cutoff.
|
||||
// Relies on monotonically non-decreasing timestamps in the log.
|
||||
qint64 lo = 0, hi = srcLog.size();
|
||||
while (lo < hi) {
|
||||
const qint64 mid = lo + (hi - lo) / 2;
|
||||
srcLog.seek(mid);
|
||||
if (mid > 0) srcLog.readLine(); // align to next line boundary
|
||||
const qint64 linePos = srcLog.pos();
|
||||
if (linePos >= hi) { hi = mid; continue; }
|
||||
const QByteArray probe = srcLog.readLine();
|
||||
if (probe.isEmpty()) { hi = mid; continue; }
|
||||
const QDateTime ts = QDateTime::fromString(
|
||||
QString::fromLatin1(probe.left(23)), "yyyy-MM-dd hh:mm:ss.zzz");
|
||||
if (!ts.isValid() || ts < cutoff)
|
||||
lo = srcLog.pos(); // this line is old, search upper half
|
||||
else
|
||||
hi = linePos; // this line is new, search lower half
|
||||
// Find the byte offset of the first log entry within the last hour by
|
||||
// walking the file backwards in blocks from EOF.
|
||||
//
|
||||
// We can't binary-search this: error dumps log multi-line payloads
|
||||
// (JSON, ADB screen XML, stack traces) whose continuation lines carry no
|
||||
// leading timestamp. A binary probe landing on such a line parsed an
|
||||
// invalid date, the old code treated that as "old" and advanced its
|
||||
// marker — and when the very last line of the file was a continuation
|
||||
// line (the usual case on error) the marker ran off the end and the dump
|
||||
// came out empty. Scanning from the tail also keeps this cheap on a huge
|
||||
// log: we stop the moment a block contains an entry older than the cutoff
|
||||
// and never touch the older prefix.
|
||||
static const qint64 BLOCK = 1 << 20; // 1 MiB
|
||||
qint64 startPos = size; // lowest offset of an in-window entry; == size => none yet
|
||||
qint64 hi = size; // region [hi, size) already scanned
|
||||
bool sawOld = false;
|
||||
while (hi > 0 && !sawOld) {
|
||||
const qint64 lo = qMax<qint64>(0, hi - BLOCK);
|
||||
srcLog.seek(lo);
|
||||
if (lo > 0) srcLog.readLine(); // skip the partial line owned by the earlier block
|
||||
qint64 pos = srcLog.pos();
|
||||
while (pos < hi) {
|
||||
const QByteArray probe = srcLog.readLine();
|
||||
if (probe.isEmpty()) break;
|
||||
const QDateTime ts = QDateTime::fromString(
|
||||
QString::fromLatin1(probe.left(23)), "yyyy-MM-dd hh:mm:ss.zzz");
|
||||
if (ts.isValid()) {
|
||||
if (ts >= cutoff) { if (pos < startPos) startPos = pos; }
|
||||
else sawOld = true; // an older entry → earlier blocks are older too
|
||||
}
|
||||
pos = srcLog.pos();
|
||||
}
|
||||
hi = lo;
|
||||
}
|
||||
srcLog.seek(lo);
|
||||
|
||||
// Nothing within the last hour → ship the whole file rather than an empty
|
||||
// one; stale error context still beats no log at all.
|
||||
srcLog.seek(startPos < size ? startPos : 0);
|
||||
|
||||
QFile dstLog(destDir + "/application.log");
|
||||
if (dstLog.open(QIODevice::WriteOnly)) {
|
||||
while (!srcLog.atEnd())
|
||||
dstLog.write(srcLog.readLine());
|
||||
dstLog.flush();
|
||||
any = true;
|
||||
}
|
||||
} else {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user