feat: add database debug logging
This commit is contained in:
parent
f15bf41bfe
commit
02b7b41b63
|
|
@ -43,7 +43,7 @@ cd ..
|
|||
./build/bin/cards /path/to/config.json
|
||||
```
|
||||
|
||||
Для подробного вывода этапов запуска и итоговой конфигурации используйте флаг `--debug`. Пароль базы данных в таком выводе не раскрывается.
|
||||
Для подробного вывода этапов запуска и итоговой конфигурации используйте флаг `--debug`. Он также включает диагностику работы с БД: создание схемы, запуск и остановку воркеров, запросы, выбранную стратегию выборки, результаты и переподключения после ошибок. Пароль базы данных в таком выводе не раскрывается.
|
||||
|
||||
```bash
|
||||
./build/bin/cards --debug
|
||||
|
|
|
|||
|
|
@ -1,13 +1,17 @@
|
|||
#include "database.hpp"
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <syncstream>
|
||||
|
||||
Database::Database(const DatabaseConfig& cfg, int workers)
|
||||
Database::Database(const DatabaseConfig& cfg, int workers, bool debug)
|
||||
: connStr(
|
||||
"host=" + cfg.host +
|
||||
" port=" + std::to_string(cfg.port) +
|
||||
" dbname=" + cfg.dbname +
|
||||
" user=" + cfg.user +
|
||||
" password=" + cfg.password) {
|
||||
" password=" + cfg.password),
|
||||
debug(debug) {
|
||||
logDebug("Creating schema for random_data");
|
||||
{
|
||||
pqxx::connection probe(connStr);
|
||||
pqxx::work txn(probe);
|
||||
|
|
@ -22,6 +26,7 @@ Database::Database(const DatabaseConfig& cfg, int workers)
|
|||
);
|
||||
txn.commit();
|
||||
}
|
||||
logDebug("Schema is ready; starting " + std::to_string(workers) + " database worker(s)");
|
||||
for (int i = 0; i < workers; ++i) {
|
||||
threadPool.emplace_back([this, i]() { worker(i); });
|
||||
}
|
||||
|
|
@ -36,16 +41,20 @@ void Database::stop() {
|
|||
std::lock_guard<std::mutex> lock(mtx);
|
||||
stopFlag = true;
|
||||
}
|
||||
logDebug("Stopping database workers");
|
||||
cv.notify_all();
|
||||
for (auto& t : threadPool) {
|
||||
if (t.joinable()) {
|
||||
t.join();
|
||||
}
|
||||
}
|
||||
logDebug("All database workers stopped");
|
||||
}
|
||||
|
||||
void Database::worker(int id) {
|
||||
logDebug("Worker " + std::to_string(id) + " connecting to database");
|
||||
auto conn = std::make_unique<pqxx::connection>(connStr);
|
||||
logDebug("Worker " + std::to_string(id) + " connected to database");
|
||||
std::mt19937 rng(std::random_device{}());
|
||||
|
||||
for (;;) {
|
||||
|
|
@ -53,7 +62,10 @@ void Database::worker(int id) {
|
|||
{
|
||||
std::unique_lock<std::mutex> lock(mtx);
|
||||
cv.wait(lock, [&] { return stopFlag || !queue.empty(); });
|
||||
if (stopFlag && queue.empty()) return;
|
||||
if (stopFlag && queue.empty()) {
|
||||
logDebug("Worker " + std::to_string(id) + " stopped");
|
||||
return;
|
||||
}
|
||||
task = std::move(queue.front());
|
||||
queue.pop();
|
||||
}
|
||||
|
|
@ -61,23 +73,36 @@ void Database::worker(int id) {
|
|||
json res;
|
||||
try {
|
||||
if (task.op == Op::RandomRecord) {
|
||||
logDebug("Worker " + std::to_string(id) + " fetching one random record");
|
||||
res = getRandomRecord(*conn, rng);
|
||||
} else {
|
||||
logDebug("Worker " + std::to_string(id) + " fetching " + std::to_string(task.count)
|
||||
+ " random record(s)");
|
||||
res = getRandomRecords(*conn, rng, task.count, task.med, task.max);
|
||||
}
|
||||
} catch (const std::exception&) {
|
||||
} catch (const std::exception& e) {
|
||||
logDebug("Worker " + std::to_string(id) + " database error: " + e.what()
|
||||
+ "; reconnecting");
|
||||
conn = std::make_unique<pqxx::connection>(connStr);
|
||||
logDebug("Worker " + std::to_string(id) + " reconnected to database");
|
||||
res = json{{"error", "Database error"}};
|
||||
}
|
||||
logDebug("Worker " + std::to_string(id) + " completed request"
|
||||
+ (res.contains("error") ? ": " + res["error"].get<std::string>() : ""));
|
||||
task.cb(std::move(res));
|
||||
}
|
||||
}
|
||||
|
||||
void Database::enqueue(Task task) {
|
||||
std::size_t queueSize;
|
||||
const char* operation = task.op == Op::RandomRecord ? "one random record" : "random records";
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mtx);
|
||||
queue.push(std::move(task));
|
||||
queueSize = queue.size();
|
||||
}
|
||||
logDebug("Queued request for " + std::string(operation)
|
||||
+ "; pending requests: " + std::to_string(queueSize));
|
||||
cv.notify_one();
|
||||
}
|
||||
|
||||
|
|
@ -91,6 +116,7 @@ void Database::getRandomRecords(int count, int med, int max, Callback cb) {
|
|||
|
||||
json Database::getRandomRecord(pqxx::connection& conn, std::mt19937& rng) {
|
||||
int totalCount = getTotalCount(conn);
|
||||
logDebug("random_data contains " + std::to_string(totalCount) + " record(s)");
|
||||
|
||||
if (totalCount == 0) {
|
||||
return json{
|
||||
|
|
@ -100,6 +126,7 @@ json Database::getRandomRecord(pqxx::connection& conn, std::mt19937& rng) {
|
|||
|
||||
std::uniform_int_distribution<int> idDist(1, totalCount);
|
||||
int randomId = idDist(rng);
|
||||
logDebug("Selected random record ID " + std::to_string(randomId));
|
||||
|
||||
pqxx::work txn(conn);
|
||||
|
||||
|
|
@ -111,6 +138,7 @@ json Database::getRandomRecord(pqxx::connection& conn, std::mt19937& rng) {
|
|||
);
|
||||
|
||||
if (result.empty()) {
|
||||
logDebug("Selected record no longer exists; falling back to the first available record");
|
||||
result = txn.exec("SELECT id, name, text, description, created_at FROM random_data LIMIT 1");
|
||||
}
|
||||
|
||||
|
|
@ -137,6 +165,7 @@ json Database::getRandomRecord(pqxx::connection& conn, std::mt19937& rng) {
|
|||
}
|
||||
|
||||
json Database::getRandomRecordsFast(pqxx::connection& conn, const int count) {
|
||||
logDebug("Using recursive CTE strategy for " + std::to_string(count) + " record(s)");
|
||||
pqxx::work txn(conn);
|
||||
|
||||
std::string query =
|
||||
|
|
@ -210,6 +239,7 @@ json Database::getRandomRecordsFast(pqxx::connection& conn, const int count) {
|
|||
}
|
||||
|
||||
txn.commit();
|
||||
logDebug("Recursive CTE returned " + std::to_string(response.size()) + " record(s)");
|
||||
|
||||
return {
|
||||
{"data", response},
|
||||
|
|
@ -220,6 +250,8 @@ json Database::getRandomRecordsFast(pqxx::connection& conn, const int count) {
|
|||
}
|
||||
|
||||
json Database::getRandomRecordsSlow(pqxx::connection& conn, std::mt19937& rng, const int count, const int totalCount) {
|
||||
logDebug("Using individual-ID strategy for " + std::to_string(count) + " of "
|
||||
+ std::to_string(totalCount) + " record(s)");
|
||||
std::set<int> ids;
|
||||
{
|
||||
std::uniform_int_distribution<int> idDist(1, totalCount);
|
||||
|
|
@ -259,6 +291,7 @@ json Database::getRandomRecordsSlow(pqxx::connection& conn, std::mt19937& rng, c
|
|||
}
|
||||
|
||||
txn.commit();
|
||||
logDebug("Individual-ID query returned " + std::to_string(response.size()) + " record(s)");
|
||||
|
||||
return {
|
||||
{"data", response},
|
||||
|
|
@ -277,6 +310,8 @@ json Database::getRandomRecords(pqxx::connection& conn, std::mt19937& rng, int c
|
|||
}
|
||||
|
||||
int totalCount = getTotalCount(conn);
|
||||
logDebug("Requested " + std::to_string(count) + " random record(s); "
|
||||
+ std::to_string(totalCount) + " available");
|
||||
|
||||
if (totalCount == 0) {
|
||||
return json{
|
||||
|
|
@ -286,10 +321,12 @@ json Database::getRandomRecords(pqxx::connection& conn, std::mt19937& rng, int c
|
|||
}
|
||||
|
||||
if (count > totalCount) {
|
||||
logDebug("Reducing requested count to available record count");
|
||||
count = totalCount;
|
||||
}
|
||||
|
||||
if (count > max) {
|
||||
logDebug("Reducing requested count to configured maximum of " + std::to_string(max));
|
||||
count = max;
|
||||
}
|
||||
|
||||
|
|
@ -329,3 +366,9 @@ std::string Database::getQueryRandomIds(const int count) {
|
|||
query += ") ORDER BY id";
|
||||
return query;
|
||||
}
|
||||
|
||||
void Database::logDebug(const std::string& message) const {
|
||||
if (debug) {
|
||||
std::osyncstream(std::cout) << "[debug][database] " << message << '\n';
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ class Database {
|
|||
public:
|
||||
using Callback = std::function<void(json)>;
|
||||
|
||||
explicit Database(const DatabaseConfig& config, int workers = 2);
|
||||
explicit Database(const DatabaseConfig& config, int workers = 2, bool debug = false);
|
||||
~Database();
|
||||
|
||||
Database(const Database&) = delete;
|
||||
|
|
@ -42,6 +42,7 @@ private:
|
|||
void worker(int id);
|
||||
void enqueue(Task task);
|
||||
void stop();
|
||||
void logDebug(const std::string& message) const;
|
||||
|
||||
json getRandomRecord(pqxx::connection& conn, std::mt19937& rng);
|
||||
json getRandomRecords(pqxx::connection& conn, std::mt19937& rng, int count, int med, int max);
|
||||
|
|
@ -56,4 +57,5 @@ private:
|
|||
std::condition_variable cv;
|
||||
std::queue<Task> queue;
|
||||
bool stopFlag = false;
|
||||
bool debug;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ int main(int argc, char* argv[]) {
|
|||
}
|
||||
|
||||
std::cout << "Connecting to database..." << std::endl;
|
||||
auto db = std::make_shared<Database>(config.database);
|
||||
auto db = std::make_shared<Database>(config.database, 2, debug);
|
||||
std::cout << "Database connected successfully!" << std::endl;
|
||||
|
||||
if (debug) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue