Skip to content
API Documentation
BastionGuard™
async_logger.hpp
Go to the documentation of this file.
1/*
2 * BastionGuard™
3 * Copyright (C) 2025–2026 Calogero Scarnà
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 *
17 * BastionGuard™ is a trademark of Calogero Scarnà.
18 * The BastionGuard™ name and branding are not licensed under the GPL.
19 */
20
21#pragma once
22#include <fstream>
23#include <string>
24#include <mutex>
25#include <queue>
26#include <thread>
27#include <chrono>
28#include <condition_variable>
29#include <filesystem>
30#include <iostream>
31#include <atomic>
32
34public:
36 static AsyncLogger inst;
37 return inst;
38 }
39
40 void log_block(const std::string& msg) {
41 if (stop_.load(std::memory_order_acquire))
42 return;
43
44 {
45 std::lock_guard<std::mutex> lock(mtx_);
46 queue_.push(timestamp() + " " + msg);
47 }
48 cv_.notify_one();
49 }
50
51 void flush() {
52 std::unique_lock<std::mutex> lock(mtx_);
53 cv_.notify_one();
54 }
55
56 void stop() {
57 bool expected = false;
58 if (!stop_.compare_exchange_strong(expected, true))
59 return; // già fermato
60
61 cv_.notify_one();
62 if (worker_.joinable())
63 worker_.join();
64 }
65
66private:
68 try {
69 std::filesystem::create_directories("/var/log/BastionGuard");
70 } catch (...) {
71 }
72
73 log_path_ = "/var/log/BastionGuard/phishing_scanner.log";
74 stop_.store(false, std::memory_order_release);
75
76 worker_ = std::thread([this]() {
77 std::unique_lock<std::mutex> lock(mtx_);
78 while (true) {
79 cv_.wait(lock, [this]() {
80 return !queue_.empty() || stop_.load(std::memory_order_acquire);
81 });
82
83 if (stop_.load(std::memory_order_acquire) && queue_.empty())
84 break;
85
86 std::queue<std::string> local_queue;
87 std::swap(local_queue, queue_);
88 lock.unlock();
89
90 try {
91 std::ofstream fout(log_path_, std::ios::app | std::ios::binary);
92 if (fout.is_open()) {
93 while (!local_queue.empty()) {
94 fout << local_queue.front() << '\n';
95 local_queue.pop();
96 }
97 fout.flush();
98 }
99 } catch (...) {
100 }
101
102 lock.lock();
103 }
104 });
105 }
106
108 stop();
109 }
110
111 static std::string timestamp() {
112 using namespace std::chrono;
113 auto now = system_clock::now();
114 std::time_t t = system_clock::to_time_t(now);
115 std::tm tm_buf{};
116 localtime_r(&t, &tm_buf);
117 char buf[64];
118 std::strftime(buf, sizeof(buf), "[%Y-%m-%d %H:%M:%S]", &tm_buf);
119 return buf;
120 }
121
122 std::thread worker_;
123 std::queue<std::string> queue_;
124 std::mutex mtx_;
125 std::condition_variable cv_;
126 std::string log_path_;
127 std::atomic<bool> stop_{false};
128};
void log_block(const std::string &msg)
std::atomic< bool > stop_
std::thread worker_
static std::string timestamp()
std::queue< std::string > queue_
std::condition_variable cv_
static AsyncLogger & instance()
std::mutex mtx_
std::string log_path_