Add bank profile and phone metadata for improved task tracking and error reporting. Update TaskDumpMeta structure and associated scripts to include bankProfileId and profilePhone. Enhance LogArchiveSender and monitoring outputs for better operator identification and debugging.
This commit is contained in:
parent
65d3b00bb9
commit
8d86d5f835
@ -37,7 +37,7 @@ void GetCardInfoScript::doStart() {
|
||||
return;
|
||||
}
|
||||
|
||||
const TaskDumpMeta dumpMeta{};
|
||||
const TaskDumpMeta dumpMeta{{}, 0, {}, {}, app.bankProfileId, app.phone};
|
||||
TaskDumpRecorder::Scope dumpScope("black", "FETCH_CARDS", m_deviceId, dumpMeta, &m_error);
|
||||
|
||||
// Читаем текущий экран
|
||||
|
||||
@ -35,7 +35,7 @@ void GetProfileInfoScript::doStart() {
|
||||
return;
|
||||
}
|
||||
|
||||
const TaskDumpMeta dumpMeta{};
|
||||
const TaskDumpMeta dumpMeta{{}, 0, {}, {}, app.bankProfileId, app.phone};
|
||||
TaskDumpRecorder::Scope dumpScope("black", "FETCH_PROFILE_INFO", m_deviceId, dumpMeta, &m_error);
|
||||
|
||||
// Читаем текущий экран
|
||||
|
||||
@ -36,7 +36,7 @@ void LoginAndCheckAccountsScript::doStart() {
|
||||
return;
|
||||
}
|
||||
|
||||
const TaskDumpMeta dumpMeta{};
|
||||
const TaskDumpMeta dumpMeta{{}, 0, {}, {}, app.bankProfileId, app.phone};
|
||||
TaskDumpRecorder::Scope dumpScope("black", "FETCH_PROFILE", m_deviceId, dumpMeta, &m_error);
|
||||
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
||||
|
||||
@ -166,22 +166,30 @@ TaskDumpRecorder::TaskDumpRecorder(const QString &bank, const QString &taskKind,
|
||||
}
|
||||
|
||||
QString TaskDumpRecorder::buildCaption(const QString &errorMessage) const {
|
||||
const QString apiToken = SettingsDAO::get("api_key");
|
||||
const QString timestamp = QDateTime::currentDateTime().toString(Qt::ISODate);
|
||||
|
||||
// api-токен в caption больше не пишем: он общий на нескольких операторов и
|
||||
// не позволяет отличить, чей профиль упал. Идентифицируем по UUID профиля,
|
||||
// материалу и телефону профиля (см. m_meta).
|
||||
QStringList head{QStringLiteral("[TASK_ERROR]")};
|
||||
if (!apiToken.isEmpty())
|
||||
head << QStringLiteral("[%1]").arg(apiToken.toHtmlEscaped());
|
||||
head << QStringLiteral("[%1]").arg(m_bank.toHtmlEscaped());
|
||||
head << QStringLiteral("[%1]").arg(m_taskKind.toHtmlEscaped());
|
||||
|
||||
QString body = QStringLiteral("Device: %1").arg(m_adbDeviceIdRaw.toHtmlEscaped());
|
||||
const QString desktopId = SettingsDAO::get("desktop_id");
|
||||
QString body;
|
||||
if (!desktopId.isEmpty())
|
||||
body += QStringLiteral("Desktop: %1\n").arg(desktopId.toHtmlEscaped());
|
||||
body += QStringLiteral("Device: %1").arg(m_adbDeviceIdRaw.toHtmlEscaped());
|
||||
if (!m_meta.bankProfileId.isEmpty())
|
||||
body += QStringLiteral("\nProfile: %1").arg(m_meta.bankProfileId.toHtmlEscaped());
|
||||
if (!m_meta.materialId.isEmpty())
|
||||
body += QStringLiteral("\nMaterial: %1").arg(m_meta.materialId.toHtmlEscaped());
|
||||
if (!m_meta.profilePhone.isEmpty())
|
||||
body += QStringLiteral("\nPhone: %1").arg(m_meta.profilePhone.toHtmlEscaped());
|
||||
if (m_meta.amount != 0)
|
||||
body += QStringLiteral("\nAmount: %1").arg(static_cast<qint64>(m_meta.amount));
|
||||
if (!m_meta.phone.isEmpty())
|
||||
body += QStringLiteral("\nPhone: %1").arg(m_meta.phone.toHtmlEscaped());
|
||||
body += QStringLiteral("\nRecipient: %1").arg(m_meta.phone.toHtmlEscaped());
|
||||
if (!m_meta.card.isEmpty())
|
||||
body += QStringLiteral("\nCard: %1").arg(m_meta.card.toHtmlEscaped());
|
||||
body += QStringLiteral("\nError: %1").arg(errorMessage.left(800).toHtmlEscaped());
|
||||
@ -238,9 +246,13 @@ void TaskDumpRecorder::finishInternal(const QString &errorMessage) {
|
||||
if (ef.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
||||
QTextStream ts(&ef);
|
||||
ts.setEncoding(QStringConverter::Utf8);
|
||||
const QString desktopId = SettingsDAO::get("desktop_id");
|
||||
if (!desktopId.isEmpty()) ts << "desktop_id: " << desktopId << "\n";
|
||||
ts << "bank: " << m_bank << "\n"
|
||||
<< "task: " << m_taskKind << "\n"
|
||||
<< "device: " << m_adbDeviceIdRaw << "\n";
|
||||
if (!m_meta.bankProfileId.isEmpty()) ts << "profile_id: " << m_meta.bankProfileId << "\n";
|
||||
if (!m_meta.profilePhone.isEmpty()) ts << "profile_phone: " << m_meta.profilePhone << "\n";
|
||||
if (!m_meta.materialId.isEmpty()) ts << "material_id: " << m_meta.materialId << "\n";
|
||||
if (m_meta.amount != 0) ts << "amount: " << static_cast<qint64>(m_meta.amount) << "\n";
|
||||
if (!m_meta.phone.isEmpty()) ts << "phone: " << m_meta.phone << "\n";
|
||||
@ -255,6 +267,17 @@ void TaskDumpRecorder::finishInternal(const QString &errorMessage) {
|
||||
const QString archivePath = m_folder + ".zip";
|
||||
const QString text = buildCaption(errorMessage);
|
||||
|
||||
// Тот же идентификатор профиля/материала/телефона добавляем в caption архива
|
||||
// логов ([LOGS]), чтобы по общему api-токену можно было разделить операторов.
|
||||
QStringList logsIdLines;
|
||||
if (!m_meta.bankProfileId.isEmpty())
|
||||
logsIdLines << QStringLiteral("Profile: %1").arg(m_meta.bankProfileId.toHtmlEscaped());
|
||||
if (!m_meta.materialId.isEmpty())
|
||||
logsIdLines << QStringLiteral("Material: %1").arg(m_meta.materialId.toHtmlEscaped());
|
||||
if (!m_meta.profilePhone.isEmpty())
|
||||
logsIdLines << QStringLiteral("Phone: %1").arg(m_meta.profilePhone.toHtmlEscaped());
|
||||
const QString logsIdentity = logsIdLines.join(QStringLiteral("\n"));
|
||||
|
||||
// Финальный скриншот шлём отдельным полем `image`, поэтому сразу читаем
|
||||
// его в память, пока папка ещё цела.
|
||||
QByteArray finalScreenshot;
|
||||
@ -265,7 +288,7 @@ void TaskDumpRecorder::finishInternal(const QString &errorMessage) {
|
||||
}
|
||||
}
|
||||
|
||||
QThread *bg = QThread::create([folder, archivePath, text, finalScreenshot]() {
|
||||
QThread *bg = QThread::create([folder, archivePath, text, finalScreenshot, logsIdentity]() {
|
||||
QByteArray archiveBytes;
|
||||
if (zipFolder(folder, archivePath)) {
|
||||
archiveBytes = readFileBytes(archivePath);
|
||||
@ -301,7 +324,7 @@ void TaskDumpRecorder::finishInternal(const QString &errorMessage) {
|
||||
// Следом — application.log + БД (+ WAL/SHM) отдельным архивом.
|
||||
// Запускаем уже ПОСЛЕ того, как task-дамп поставлен в очередь
|
||||
// отправки, чтобы порядок прихода на relay был "дамп → логи".
|
||||
LogArchiveSender::dispatch(QStringLiteral("TASK_ERROR"));
|
||||
LogArchiveSender::dispatch(QStringLiteral("TASK_ERROR"), -1, logsIdentity);
|
||||
});
|
||||
QObject::connect(bg, &QThread::finished, bg, &QObject::deleteLater);
|
||||
bg->start();
|
||||
|
||||
@ -9,8 +9,10 @@ class NetworkService;
|
||||
struct TaskDumpMeta {
|
||||
QString materialId;
|
||||
double amount = 0; // 0 = нет
|
||||
QString phone; // пусто = нет
|
||||
QString phone; // пусто = нет (телефон получателя в транзакции)
|
||||
QString card; // пусто = нет
|
||||
QString bankProfileId; // серверный UUID банковского профиля (детект в общих логах)
|
||||
QString profilePhone; // телефон банковского профиля (не получателя)
|
||||
};
|
||||
|
||||
class TaskDumpRecorder {
|
||||
|
||||
@ -36,7 +36,7 @@ void GetCardInfoScript::doStart() {
|
||||
return;
|
||||
}
|
||||
|
||||
const TaskDumpMeta dumpMeta{};
|
||||
const TaskDumpMeta dumpMeta{{}, 0, {}, {}, app.bankProfileId, app.phone};
|
||||
TaskDumpRecorder::Scope dumpScope("dushanbe", "FETCH_CARDS", m_deviceId, dumpMeta, &m_error);
|
||||
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
||||
|
||||
@ -276,7 +276,7 @@ void GetLastTransactionsScript::doStart() {
|
||||
}
|
||||
|
||||
const double firstAmount = m_targets.isEmpty() ? 0.0 : m_targets.first().first;
|
||||
const TaskDumpMeta dumpMeta{m_materialId, firstAmount, {}, {}};
|
||||
const TaskDumpMeta dumpMeta{m_materialId, firstAmount, {}, {}, app.bankProfileId, app.phone};
|
||||
TaskDumpRecorder::Scope dumpScope("dushanbe", "FETCH_TRANSACTIONS", m_deviceId, dumpMeta, &m_error);
|
||||
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
||||
|
||||
@ -39,7 +39,7 @@ void GetProfileInfoScript::doStart() {
|
||||
return;
|
||||
}
|
||||
|
||||
const TaskDumpMeta dumpMeta{};
|
||||
const TaskDumpMeta dumpMeta{{}, 0, {}, {}, app.bankProfileId, app.phone};
|
||||
TaskDumpRecorder::Scope dumpScope("dushanbe", "FETCH_PROFILE_INFO", m_deviceId, dumpMeta, &m_error);
|
||||
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
||||
|
||||
@ -41,7 +41,7 @@ void LoginAndCheckAccountsScript::doStart() {
|
||||
return;
|
||||
}
|
||||
|
||||
const TaskDumpMeta dumpMeta{};
|
||||
const TaskDumpMeta dumpMeta{{}, 0, {}, {}, app.bankProfileId, app.phone};
|
||||
TaskDumpRecorder::Scope dumpScope("dushanbe", "FETCH_PROFILE", m_deviceId, dumpMeta, &m_error);
|
||||
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
||||
|
||||
@ -123,7 +123,7 @@ void PayByCardScript::doStart() {
|
||||
return;
|
||||
}
|
||||
|
||||
const TaskDumpMeta dumpMeta{m_account.materialId, m_amount, {}, m_cardNumber};
|
||||
const TaskDumpMeta dumpMeta{m_account.materialId, m_amount, {}, m_cardNumber, app.bankProfileId, app.phone};
|
||||
TaskDumpRecorder::Scope dumpScope("dushanbe", "CREATE_TRANSACTION_CARD", device.adbSerial, dumpMeta, &m_error);
|
||||
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(device.adbSerial, ++m_counter));
|
||||
|
||||
@ -120,7 +120,7 @@ void PayByPhoneScript::doStart() {
|
||||
return;
|
||||
}
|
||||
|
||||
const TaskDumpMeta dumpMeta{m_account.materialId, m_amount, m_phone, {}};
|
||||
const TaskDumpMeta dumpMeta{m_account.materialId, m_amount, m_phone, {}, app.bankProfileId, app.phone};
|
||||
TaskDumpRecorder::Scope dumpScope("dushanbe", "CREATE_TRANSACTION_PHONE", device.adbSerial, dumpMeta, &m_error);
|
||||
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(device.adbSerial, ++m_counter));
|
||||
|
||||
@ -42,7 +42,7 @@ void GetCardInfoScript::doStart() {
|
||||
return;
|
||||
}
|
||||
|
||||
const TaskDumpMeta dumpMeta{};
|
||||
const TaskDumpMeta dumpMeta{{}, 0, {}, {}, app.bankProfileId, app.phone};
|
||||
TaskDumpRecorder::Scope dumpScope("ozon", "FETCH_CARDS", m_deviceId, dumpMeta, &m_error);
|
||||
|
||||
// Читаем текущий экран
|
||||
|
||||
@ -109,7 +109,7 @@ void GetLastTransactionsScript::doStart() {
|
||||
}
|
||||
|
||||
const double firstAmount = m_targets.isEmpty() ? 0.0 : m_targets.first().first;
|
||||
const TaskDumpMeta dumpMeta{m_materialId, firstAmount, {}, {}};
|
||||
const TaskDumpMeta dumpMeta{m_materialId, firstAmount, {}, {}, app.bankProfileId, app.phone};
|
||||
TaskDumpRecorder::Scope dumpScope("ozon", "FETCH_TRANSACTIONS", m_deviceId, dumpMeta, &m_error);
|
||||
|
||||
if (!navigateToTransactionList(device, app)) {
|
||||
|
||||
@ -37,7 +37,7 @@ void GetProfileInfoScript::doStart() {
|
||||
return;
|
||||
}
|
||||
|
||||
const TaskDumpMeta dumpMeta{};
|
||||
const TaskDumpMeta dumpMeta{{}, 0, {}, {}, app.bankProfileId, app.phone};
|
||||
TaskDumpRecorder::Scope dumpScope("ozon", "FETCH_PROFILE_INFO", m_deviceId, dumpMeta, &m_error);
|
||||
|
||||
// Читаем текущий экран
|
||||
|
||||
@ -40,7 +40,7 @@ void LoginAndCheckAccountsScript::doStart() {
|
||||
return;
|
||||
}
|
||||
|
||||
const TaskDumpMeta dumpMeta{};
|
||||
const TaskDumpMeta dumpMeta{{}, 0, {}, {}, app.bankProfileId, app.phone};
|
||||
TaskDumpRecorder::Scope dumpScope("ozon", "FETCH_PROFILE", m_deviceId, dumpMeta, &m_error);
|
||||
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
||||
|
||||
@ -91,7 +91,7 @@ void PayByCardScript::doStart() {
|
||||
}
|
||||
|
||||
const QString &adbId = device.adbSerial;
|
||||
const TaskDumpMeta dumpMeta{m_account.materialId, m_amount, {}, m_cardNumber};
|
||||
const TaskDumpMeta dumpMeta{m_account.materialId, m_amount, {}, m_cardNumber, app.bankProfileId, app.phone};
|
||||
TaskDumpRecorder::Scope dumpScope("ozon", "CREATE_TRANSACTION_CARD", adbId, dumpMeta, &m_error);
|
||||
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(adbId, ++m_counter));
|
||||
|
||||
@ -100,7 +100,7 @@ void PayByPhoneScript::doStart() {
|
||||
}
|
||||
|
||||
const QString &adbId = device.adbSerial;
|
||||
const TaskDumpMeta dumpMeta{m_account.materialId, m_amount, m_phone, {}};
|
||||
const TaskDumpMeta dumpMeta{m_account.materialId, m_amount, m_phone, {}, app.bankProfileId, app.phone};
|
||||
TaskDumpRecorder::Scope dumpScope("ozon", "CREATE_TRANSACTION_PHONE", adbId, dumpMeta, &m_error);
|
||||
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(adbId, ++m_counter));
|
||||
|
||||
@ -34,7 +34,7 @@
|
||||
#include "dushanbe/PayByPhoneScript.h"
|
||||
|
||||
static void sendTaskResult(const QString &type, const QString &materialId, const QString &bankName, const QJsonValue &data, int eventId = -1, bool updateStatus = true);
|
||||
static void sendTaskError(const QString &type, const QString &materialId, const QString &bankName, const QString &description, const QByteArray &screenshot = {}, int eventId = -1, const QString &transactionId = {});
|
||||
static void sendTaskError(const QString &type, const QString &materialId, const QString &bankName, const QString &description, const QByteArray &screenshot = {}, int eventId = -1, const QString &transactionId = {}, int accountId = -1);
|
||||
static void sendMonitoringLog(const QString &type, const QString &event, const QString &message, const QByteArray &image = {}, int eventId = -1, bool toApiBase = false);
|
||||
|
||||
EventHandler::EventHandler(QObject *parent) : QObject(parent) {}
|
||||
@ -78,7 +78,7 @@ void EventHandler::start() {
|
||||
if (e.sentToServer) continue;
|
||||
EventDAO::updateEvent(e.id, EventStatus::Error, "App restarted");
|
||||
EventDAO::markSentToServer(e.id);
|
||||
sendTaskError(eventTypeToString(e.type), e.externalId, e.bankName, "App restarted, event was pending", {}, -1, e.transactionId);
|
||||
sendTaskError(eventTypeToString(e.type), e.externalId, e.bankName, "App restarted, event was pending", {}, -1, e.transactionId, e.accountId);
|
||||
qDebug() << "[EventHandler] Closed stale event id:" << e.id;
|
||||
}
|
||||
}
|
||||
@ -127,7 +127,7 @@ void EventHandler::onTasksReceived(const QJsonArray &tasks) {
|
||||
if (eventType == EventType::FetchProfile) {
|
||||
const QList<EventInfo> cancelled = EventDAO::cancelWaitingByMaterial(materialId, EventType::FetchProfile);
|
||||
for (const EventInfo &c : cancelled) {
|
||||
sendTaskError(eventTypeToString(c.type), c.externalId, c.bankName, "Cancelled: replaced by new task", {}, -1, c.transactionId);
|
||||
sendTaskError(eventTypeToString(c.type), c.externalId, c.bankName, "Cancelled: replaced by new task", {}, -1, c.transactionId, c.accountId);
|
||||
EventDAO::markSentToServer(c.id);
|
||||
}
|
||||
}
|
||||
@ -168,7 +168,7 @@ void EventHandler::onTasksReceived(const QJsonArray &tasks) {
|
||||
if (!onlineDevices.contains(account.deviceId)) {
|
||||
qWarning() << "[EventHandler] Device offline for material_id:" << materialId << "device:" << account.deviceId;
|
||||
EventDAO::updateEvent(eventId, EventStatus::Error, "Device is offline");
|
||||
sendTaskError(typeStr, materialId, bankName, "Device is offline", {}, -1, incomingTransactionId);
|
||||
sendTaskError(typeStr, materialId, bankName, "Device is offline", {}, -1, incomingTransactionId, account.id);
|
||||
}
|
||||
}
|
||||
|
||||
@ -215,7 +215,7 @@ static void sendTaskResult(const QString &type, const QString &materialId, const
|
||||
|
||||
static void sendTaskError(const QString &type, const QString &materialId, const QString &bankName,
|
||||
const QString &description, const QByteArray &screenshot, int eventId,
|
||||
const QString &transactionId) {
|
||||
const QString &transactionId, int accountId) {
|
||||
QJsonObject errorData;
|
||||
errorData["status"] = QStringLiteral("error");
|
||||
errorData["event_type"] = type;
|
||||
@ -224,18 +224,36 @@ static void sendTaskError(const QString &type, const QString &materialId, const
|
||||
errorData["transaction_id"] = transactionId;
|
||||
sendTaskResult(QStringLiteral("ERROR"), materialId, bankName, errorData, eventId);
|
||||
|
||||
if (!screenshot.isEmpty()) {
|
||||
const QString apiToken = SettingsDAO::get("api_key");
|
||||
// Шлём в мониторинг всегда — даже без скриншота (offline / expired /
|
||||
// disabled / account not found и т.п.), чтобы такие ошибки не «молчали» на
|
||||
// релее. Скриншот прикладываем, если он есть.
|
||||
// api-токен общий на нескольких операторов — по нему не отличить, чей
|
||||
// профиль упал. Резолвим банковский профиль по accountId и пишем его
|
||||
// серверный UUID + материал + телефон профиля.
|
||||
QString profileUuid, profilePhone;
|
||||
if (accountId > 0) {
|
||||
const MaterialInfo acc = MaterialDAO::getAccountById(accountId);
|
||||
if (acc.id != -1) {
|
||||
const BankProfileInfo app = BankProfileDAO::getApplication(acc.deviceId, acc.appCode);
|
||||
profileUuid = app.bankProfileId;
|
||||
profilePhone = app.phone;
|
||||
}
|
||||
}
|
||||
const QString desktopId = SettingsDAO::get("desktop_id");
|
||||
QStringList lines;
|
||||
lines << QStringLiteral("<b>[TASK_ERROR] [%1] [%2]</b>")
|
||||
.arg(type.toHtmlEscaped(), bankName.toUpper().toHtmlEscaped());
|
||||
if (!apiToken.isEmpty())
|
||||
lines << QStringLiteral("<b>[%1]</b>").arg(apiToken.toHtmlEscaped());
|
||||
lines << QStringLiteral("<b>[%1]</b>").arg(materialId.toHtmlEscaped());
|
||||
lines << description.toHtmlEscaped();
|
||||
if (!desktopId.isEmpty())
|
||||
lines << QStringLiteral("Desktop: %1").arg(desktopId.toHtmlEscaped());
|
||||
if (!profileUuid.isEmpty())
|
||||
lines << QStringLiteral("Profile: %1").arg(profileUuid.toHtmlEscaped());
|
||||
if (!materialId.isEmpty())
|
||||
lines << QStringLiteral("Material: %1").arg(materialId.toHtmlEscaped());
|
||||
if (!profilePhone.isEmpty())
|
||||
lines << QStringLiteral("Phone: %1").arg(profilePhone.toHtmlEscaped());
|
||||
lines << QStringLiteral("Error: %1").arg(description.toHtmlEscaped());
|
||||
const QString message = lines.join(QStringLiteral("\n"));
|
||||
sendMonitoringLog("error", "task_error", message, screenshot, eventId);
|
||||
}
|
||||
|
||||
// application.log + БД отправляются из TaskDumpRecorder::finishInternal,
|
||||
// чтобы покрывать также non-event-driven задачи (login flow и т.п.).
|
||||
@ -359,7 +377,7 @@ void EventHandler::updateEventThread(const QString &key, const EventInfo &event,
|
||||
.arg(eventTypeToString(event.type), deviceLabel, event.bankName, result);
|
||||
GeneralLogDAO::insert("CRITICAL", "EventHandler", logMsg, screenshot);
|
||||
|
||||
sendTaskError(eventTypeToString(event.type), event.externalId, event.bankName, result, screenshot, event.id, event.transactionId);
|
||||
sendTaskError(eventTypeToString(event.type), event.externalId, event.bankName, result, screenshot, event.id, event.transactionId, event.accountId);
|
||||
|
||||
if (event.type == EventType::CreateTransaction) {
|
||||
const MaterialInfo declAcc = MaterialDAO::getAccountById(event.accountId);
|
||||
@ -750,7 +768,7 @@ void EventHandler::startThreadForTask(const MaterialInfo &account, const EventIn
|
||||
const QString logMsg = QString("[%1] bank=%2 material=%3: Script timeout")
|
||||
.arg(eventTypeToString(event.type), event.bankName, event.externalId);
|
||||
GeneralLogDAO::insert("CRITICAL", "EventHandler", logMsg);
|
||||
sendTaskError(eventTypeToString(event.type), event.externalId, event.bankName, "Script timeout (5 min)", {}, -1, event.transactionId);
|
||||
sendTaskError(eventTypeToString(event.type), event.externalId, event.bankName, "Script timeout (5 min)", {}, -1, event.transactionId, event.accountId);
|
||||
EventDAO::markSentToServer(event.id);
|
||||
|
||||
// Убиваем банковское приложение на устройстве после таймаута
|
||||
@ -787,7 +805,7 @@ void EventHandler::processNextTask(const QString &deviceId) {
|
||||
if (waitSecs > 5 * 60) {
|
||||
qWarning() << "[EventHandler] Task expired after" << waitSecs << "s, event id:" << event.id;
|
||||
EventDAO::updateEvent(event.id, EventStatus::Error, "Task expired: waited " + QString::number(waitSecs) + "s");
|
||||
sendTaskError(eventTypeToString(event.type), event.externalId, event.bankName, "Task expired: not started within 5 minutes", {}, -1, event.transactionId);
|
||||
sendTaskError(eventTypeToString(event.type), event.externalId, event.bankName, "Task expired: not started within 5 minutes", {}, -1, event.transactionId, event.accountId);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -797,7 +815,7 @@ void EventHandler::processNextTask(const QString &deviceId) {
|
||||
qWarning() << "[EventHandler] Bank profile disabled for" << account.appCode << "device:" << deviceId;
|
||||
EventDAO::updateEvent(event.id, EventStatus::Error, "Bank profile is disabled");
|
||||
sendTaskError(eventTypeToString(event.type), event.externalId, event.bankName,
|
||||
"Bank profile is disabled: " + account.appCode, {}, -1, event.transactionId);
|
||||
"Bank profile is disabled: " + account.appCode, {}, -1, event.transactionId, event.accountId);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@ -90,16 +90,22 @@ QByteArray buildArchive() {
|
||||
|
||||
} // namespace
|
||||
|
||||
bool LogArchiveSender::dispatch(const QString &label, int eventId) {
|
||||
bool LogArchiveSender::dispatch(const QString &label, int eventId, const QString &extraCaptionHtml) {
|
||||
const QString apiToken = SettingsDAO::get("api_key");
|
||||
const QDateTime now = QDateTime::currentDateTime();
|
||||
const QString timestamp = now.toString(Qt::ISODate);
|
||||
|
||||
// api-токен в caption больше не пишем (общий на нескольких операторов);
|
||||
// идентификация идёт по Profile/Material/Phone из extraCaptionHtml.
|
||||
const QString desktopId = SettingsDAO::get("desktop_id");
|
||||
QStringList head{QStringLiteral("[LOGS]")};
|
||||
if (!apiToken.isEmpty()) head << QStringLiteral("[%1]").arg(apiToken.toHtmlEscaped());
|
||||
if (!label.isEmpty()) head << QStringLiteral("[%1]").arg(label.toHtmlEscaped());
|
||||
const QString text = QStringLiteral("<b>%1</b>\n%2")
|
||||
QString text = QStringLiteral("<b>%1</b>\n%2")
|
||||
.arg(head.join(QStringLiteral(" ")), timestamp.toHtmlEscaped());
|
||||
if (!desktopId.isEmpty())
|
||||
text += QStringLiteral("\nDesktop: %1").arg(desktopId.toHtmlEscaped());
|
||||
if (!extraCaptionHtml.isEmpty())
|
||||
text += QStringLiteral("\n") + extraCaptionHtml;
|
||||
|
||||
QString tokenSafe = apiToken;
|
||||
tokenSafe.replace(QRegularExpression(R"([^\w\-.])"), "_");
|
||||
|
||||
@ -10,7 +10,10 @@ namespace LogArchiveSender {
|
||||
// в собственных background-потоках (worker для zip + thread для HTTP).
|
||||
// `label` — короткий тег ("TASK_ERROR" и т.п.), попадает в caption и в имя файла.
|
||||
// `eventId` (если > 0) тоже уходит в имя файла для трассировки.
|
||||
// `extraCaptionHtml` (если не пусто) — дополнительные строки caption'а
|
||||
// (Profile/Material/Phone), уже экранированные; нужны чтобы по общему
|
||||
// api-токену различать операторов.
|
||||
// Возвращает true если задача поставлена в очередь; реальный результат отправки
|
||||
// не отслеживается (fire-and-forget, как у sendMonitoringLog).
|
||||
bool dispatch(const QString &label, int eventId = -1);
|
||||
bool dispatch(const QString &label, int eventId = -1, const QString &extraCaptionHtml = {});
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user