Init public repo

This commit is contained in:
2026-08-13 14:35:01 +07:00
commit 83161921a1
14 changed files with 399 additions and 0 deletions
+18
View File
@@ -0,0 +1,18 @@
CC = g++
all: app Saver clean
clean:
rm -rf *.o
app: Saver
${CC} src/app/UserInput/UserInput.cpp -o UserInput.o -c
${CC} src/app/SaverLib.cpp -o SaverLib.o -c
${CC} src/app/main.cpp -o main.o -c
${CC} src/app/SaveThread/SaveThread.cpp -o SaveThread.o -c
${CC} main.o SaveThread.o SaverLib.o UserInput.o -o app -ldl
Saver:
${CC} src/Saver/Saver.cpp -o Saver.o -fPIC -c
${CC} src/Saver/SaverBuilder.cpp -o SaverBuilder.o -fPIC -c
${CC} -shared Saver.o SaverBuilder.o -o libsaver.so
+20
View File
@@ -0,0 +1,20 @@
# Saver
Это программа для логирования сообщений
# Сборка
Запустите в корне make
# Использование
```bash
./app <log_file> <base_importance>
```
Существует 3 уровня важности:
- Low
- Middle
- High
Далее программа будет поочерёдно просить ввести сообщение и его важность. Если ничего не вводить или ввести не коректно в поле важности то будет присовено значение base_importance.
+57
View File
@@ -0,0 +1,57 @@
#pragma once
#include <string>
#include <stdexcept>
/*
* Интерфейс сохранялки.
*/
class ISaver
{
public:
enum ImportanceMessage
{
Low = 0,
Middle = 1,
High = 2
};
/*
* @throw std::runtime_error
*/
inline static std::string ImportanceMessageToString(ImportanceMessage val)
{
switch (val)
{
case Low:
return "Low";
case Middle:
return "Middle";
case High:
return "High";
}
throw std::runtime_error("[ISaver::ImportanceMessageToString] invalid value");
}
/*
* @throw std::runtime_error
*/
inline static ImportanceMessage StringToImportanceMessage(const std::string& str)
{
if (str == "Low")
return Low;
else if (str == "Middle")
return Middle;
else if (str == "High")
return High;
throw std::runtime_error("[ISaver::StringToImportanceMessage] Invalid importance value");
}
virtual ~ISaver() = default;
/*
* Может бросать исключения.
*/
virtual void save(const std::string& msg, ImportanceMessage importance) = 0;
virtual void set_base_importance(ImportanceMessage min_importance) = 0;
};
+46
View File
@@ -0,0 +1,46 @@
#include "Saver.h"
#include <fstream>
#include <stdexcept>
#include <chrono>
#include <ctime>
Saver::Saver(const std::string& log_file, ImportanceMessage min_importance):
log_file_(log_file),
min_importance_(min_importance)
{}
void Saver::save(const std::string& msg, ImportanceMessage importance)
{
if (importance < min_importance_.load())
return;
std::scoped_lock lock(m_db_file_);
std::ofstream file(log_file_, std::ios::app);
if (file.is_open() == false)
throw std::runtime_error("[Saver::save] Fail open" + log_file_);
// Получение текущего времени и преобразование его в строку
auto now = std::chrono::system_clock::now();
std::time_t t_c = std::chrono::system_clock::to_time_t(now);
char* date = ctime(&t_c);
for (int i = 0; date[i] != 0; ++ i)
{
if (date[i] == '\n')
{
date[i] = 0;
break;
}
}
file << "[" << date << "] [" << ImportanceMessageToString(importance) << "] " << msg << '\n';
file.close();
}
void Saver::set_base_importance(ImportanceMessage min_importance)
{
min_importance_.store(min_importance);
}
+27
View File
@@ -0,0 +1,27 @@
#pragma once
#include "ISaver.h"
#include <mutex>
#include <atomic>
/*
* Реализация сохранялки.
* Класс потокобезопасен.
*/
class Saver : public ISaver
{
std::mutex m_db_file_;
std::string log_file_;
std::atomic<ImportanceMessage> min_importance_;
public:
Saver(const std::string& log_file, ImportanceMessage min_importance);
/*
* @throw std::runtime_error("Fail open <log_file>")
*/
void save(const std::string& msg, ImportanceMessage importance) override;
void set_base_importance(ImportanceMessage min_importance) override;
};
+20
View File
@@ -0,0 +1,20 @@
#include "Saver.h"
#include <mutex>
#include <string>
static ISaver* saver_obj = nullptr;
static std::mutex m_saver_obj;
extern "C" {
ISaver* BuildSaver(const std::string& log_file, ISaver::ImportanceMessage min_importance)
{
if (saver_obj == nullptr)
{
std::scoped_lock lock(m_saver_obj);
if (saver_obj == nullptr)
saver_obj = new Saver(log_file, min_importance);
}
return saver_obj;
}
}
+11
View File
@@ -0,0 +1,11 @@
#pragma once
#include "../../Saver/ISaver.h"
class ISaveThread
{
public:
virtual ~ISaveThread() = default;
virtual void save(const std::string& msg, ISaver::ImportanceMessage importance) = 0;
};
+46
View File
@@ -0,0 +1,46 @@
#include "SaveThread.h"
#include <chrono>
#include <iostream>
SaveThread::SaveThread(SaverLib& saver) : saver_(saver)
{
is_runing_.store(true);
save_thread_ = std::make_unique<std::thread>([this] { SaveThreadMethod(); });
}
void SaveThread::SaveThreadMethod()
{
// поток может завершится только если не будет сообщений в очереди, иначе он сначала все сохранит
while(is_runing_.load() || queue_.empty() == false)
{
// Небольшая задержка для разгрузки CPU
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::scoped_lock lock(m_queue_);
if (queue_.empty())
continue;
Msg msg = queue_.front();
try {
saver_->save(msg.msg, msg.importance);
queue_.pop_front();
} catch (const std::exception& e) {
std::cerr << e.what() << '\n';
std::this_thread::sleep_for(std::chrono::milliseconds(500));
continue;
}
}
}
SaveThread::~SaveThread()
{
is_runing_.store(false);
save_thread_->join();
}
void SaveThread::save(const std::string& msg, ISaver::ImportanceMessage importance)
{
std::scoped_lock lock(m_queue_);
queue_.push_back(Msg {msg, importance});
}
+35
View File
@@ -0,0 +1,35 @@
#pragma once
#include "ISaveThread.h"
#include "../SaverLib.h"
#include <thread>
#include <atomic>
#include <mutex>
#include <list>
#include <memory>
class SaveThread : public ISaveThread
{
struct Msg
{
std::string msg;
ISaver::ImportanceMessage importance;
};
SaverLib& saver_;
std::list<Msg> queue_;
std::mutex m_queue_;
/*
* Поток сохранения логов
*/
std::unique_ptr<std::thread> save_thread_;
void SaveThreadMethod();
std::atomic_bool is_runing_;
public:
SaveThread(SaverLib& saver);
~SaveThread();
void save(const std::string& msg, ISaver::ImportanceMessage importance) override;
};
+24
View File
@@ -0,0 +1,24 @@
#include "SaverLib.h"
#include <dlfcn.h>
typedef ISaver*(*BuildSaver)(const std::string&, ISaver::ImportanceMessage);
SaverLib::SaverLib(const std::string& log_file, ISaver::ImportanceMessage importance)
{
handle = dlopen("./libsaver.so", RTLD_LAZY);
if (handle == nullptr)
throw std::runtime_error(dlerror());
BuildSaver builder = reinterpret_cast<BuildSaver>(dlsym(handle, "BuildSaver"));
if(builder == nullptr)
throw std::runtime_error(dlerror());
saver = builder(log_file, importance);
}
SaverLib::~SaverLib()
{
delete saver;
dlclose(handle);
}
+16
View File
@@ -0,0 +1,16 @@
#pragma once
#include "../Saver/ISaver.h"
class SaverLib
{
void* handle;
ISaver* saver;
public:
SaverLib(const std::string& log_file, ISaver::ImportanceMessage importance);
inline ISaver* operator->()
{
return saver;
}
~SaverLib();
};
+36
View File
@@ -0,0 +1,36 @@
#include "UserInput.h"
#include <string>
#include <iostream>
UserInput::UserInput(ISaveThread& save_thread, ISaver::ImportanceMessage base_importance) : save_thread_(save_thread), base_importance_(base_importance) {}
void UserInput::start()
{
while(true)
{
std::string msg, str_importance;
std::cout << "Enter message (Enter \"" << quit_msg << "\" for quit)> ";
std::getline(std::cin, msg);
if(quit_msg == msg)
return;
std::cout << "Enter importance (default: " << ISaver::ImportanceMessageToString(base_importance_) << ")> ";
std::getline(std::cin, str_importance);
// Set default value
ISaver::ImportanceMessage importance = base_importance_;
if(str_importance.empty() == false)
{
try {
importance = ISaver::StringToImportanceMessage(str_importance);
} catch (const std::exception& e) {
std::cout << e.what() << '\n';
importance = base_importance_;
std::cout << "Set The value has been set " << ISaver::ImportanceMessageToString(base_importance_) << '\n';
}
}
save_thread_.save(msg, importance);
}
}
+14
View File
@@ -0,0 +1,14 @@
#pragma once
#include "../SaveThread/ISaveThread.h"
class UserInput
{
ISaveThread& save_thread_;
ISaver::ImportanceMessage base_importance_;
const char* quit_msg = "!quit";
public:
UserInput(ISaveThread& save_thread, ISaver::ImportanceMessage base_importance);
void start();
};
+29
View File
@@ -0,0 +1,29 @@
#include <iostream>
#include <memory>
#include "SaveThread/SaveThread.h"
#include "SaverLib.h"
#include "UserInput/UserInput.h"
int main(int argc, char* argv[])
{
if (argc < 3)
{
std::cerr << "app <log_file_name> <base_importance>\n";
return 0;
}
std::string str_importance = argv[2];
ISaver::ImportanceMessage base_importance = ISaver::StringToImportanceMessage(str_importance);
SaverLib saver_lib(argv[1], base_importance);
SaveThread save_thread(saver_lib);
//save_thread.save("test_low", ISaver::ImportanceMessage::Low);
//save_thread.save("test_high", ISaver::ImportanceMessage::High);
UserInput ui(save_thread, base_importance);
ui.start();
return 0;
}