Init public repo
This commit is contained in:
@@ -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
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# Saver
|
||||||
|
Это программа для логирования сообщений
|
||||||
|
|
||||||
|
# Сборка
|
||||||
|
Запустите в корне make
|
||||||
|
|
||||||
|
# Использование
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./app <log_file> <base_importance>
|
||||||
|
```
|
||||||
|
|
||||||
|
Существует 3 уровня важности:
|
||||||
|
- Low
|
||||||
|
- Middle
|
||||||
|
- High
|
||||||
|
|
||||||
|
Далее программа будет поочерёдно просить ввести сообщение и его важность. Если ничего не вводить или ввести не коректно в поле важности то будет присовено значение base_importance.
|
||||||
|
|
||||||
|
|
||||||
@@ -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;
|
||||||
|
};
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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;
|
||||||
|
};
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
};
|
||||||
@@ -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});
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
};
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
};
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
};
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user