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