ImSQL
C++ 기반 SQL 자동화 및 라이선스 관리 엔진
Loading...
Searching...
No Matches
log.hpp
Go to the documentation of this file.
1
13#pragma once
14
15#ifndef SQLOG_H
16#define SQLOG_H
17
18#include <iostream>
19#include <fstream>
20#include <sstream>
21#include <string>
22#include <ctime>
23#include <cstdarg>
24#include <mutex>
25#include <format>
26#include <thread>
27#include <queue>
28#include <condition_variable>
29#include <filesystem>
30
31#ifdef _DEBUG
32#include "ename.c.inc"
33#endif
34
35#ifdef _WIN32
36#include <windows.h>
37#include <direct.h>
38#define mkdir(path, mode) _mkdir(path)
39#else
40#include <unistd.h>
41#include <sys/stat.h>
42#endif
43
44#define SQLOGD_BUF_SIZE 4096
45#define RESOURCE_PATH "./output"
46
47namespace utils {
48
56inline std::mutex log_mutex;
57inline std::queue<std::string> log_queue;
58inline std::condition_variable log_cv;
59inline bool log_thread_running = true;
60
66inline std::string getTimeString() {
67 char buffer[20];
68 std::time_t now = std::time(nullptr);
69 std::tm tm;
70#ifdef _WIN32
71 localtime_s(&tm, &now);
72#else
73 localtime_r(&now, &tm);
74#endif
75 std::strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &tm);
76 return std::string(buffer);
77}
78
84inline void ensureDirectoryExists(const std::string& dirPath) {
85 std::error_code ec;
86 std::filesystem::create_directories(dirPath, ec);
87 if (ec) {
88 std::cerr << "[LOGGER] Directory create failed: " << dirPath << " - " << ec.message() << std::endl;
89 }
90}
91
98inline std::string getLogFilePath(const std::string& level) {
100 return std::string(RESOURCE_PATH) + "/" + level + ".log";
101}
102
108inline void logThreadFunc() {
109 while (log_thread_running) {
110 std::unique_lock<std::mutex> lock(log_mutex);
111 log_cv.wait(lock, [] { return !log_queue.empty() || !log_thread_running; });
112
113 while (!log_queue.empty()) {
114 std::string log_entry = log_queue.front();
115 log_queue.pop();
116 lock.unlock();
117
118 std::string level = log_entry.substr(1, log_entry.find(']') - 1);
119 std::ofstream log_file(getLogFilePath(level), std::ios::app);
120 if (log_file.is_open()) {
121 log_file << log_entry;
122 }
123
124 lock.lock();
125 }
126 }
127}
128
132inline std::thread log_thread(logThreadFunc);
133
143inline void COUT_(const std::string& log_level, const std::string& function, int line, const char* format_str, ...) {
144 char buf[SQLOGD_BUF_SIZE];
145 va_list args;
146 va_start(args, format_str);
147 vsnprintf(buf, SQLOGD_BUF_SIZE, format_str, args);
148 va_end(args);
149
150 std::ostringstream logMsg;
151
152#ifdef _DEBUG
153 if (log_level == "ERROR" || log_level == "FATAL") {
154 int err = errno;
155 if (err > 0 && err < MAX_ENAME && ename[err][0] != '\0') {
156 std::ostringstream err_info;
157 err_info << " | errno=" << err << " (" << ename[err] << ")";
158 strncat(buf, err_info.str().c_str(), SQLOGD_BUF_SIZE - strlen(buf) - 1);
159 }
160 }
161#endif
162
163#ifdef _DEBUG
164 logMsg << "[" << log_level << "] [" << getTimeString() << "] (" << function << ":" << line << ") - " << buf << "\n";
165#else
166 logMsg << "[" << log_level << "] [" << getTimeString() << "] - " << buf << "\n";
167#endif
168
169#ifdef _DEBUG
170 {
171 std::lock_guard<std::mutex> lock(log_mutex);
172 log_queue.push(logMsg.str());
173 }
174 log_cv.notify_one();
175#endif
176
177#ifdef _WIN32
178 HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
179 if (log_level == "ERROR") SetConsoleTextAttribute(hConsole, 12);
180 else if (log_level == "FATAL") SetConsoleTextAttribute(hConsole, 206);
181 else if (log_level == "WARN") SetConsoleTextAttribute(hConsole, 14);
182 else if (log_level == "INFO") SetConsoleTextAttribute(hConsole, 10);
183 else SetConsoleTextAttribute(hConsole, 7);
184#endif
185
186 std::cout << logMsg.str();
187
188#ifdef _WIN32
189 SetConsoleTextAttribute(hConsole, 7);
190#endif
191
192 if (log_level == "FATAL") {
193 std::exit(EXIT_FAILURE);
194 }
195}
196
200inline void stopLogThread() {
201 log_thread_running = false;
202 log_cv.notify_all();
203 if (log_thread.joinable()) log_thread.join();
204}
205
206} // namespace utils
207
208// 로그 매크로 정의
209#define SQLOG_I(format_str, ...) ::utils::COUT_("INFO", __func__, __LINE__, format_str, ##__VA_ARGS__) //< @brief INFO 레벨 로그
210#define SQLOG_E(format_str, ...) ::utils::COUT_("ERROR", __func__, __LINE__, format_str, ##__VA_ARGS__) //< @brief ERROR 레벨 로그
211#define SQLOG_F(format_str, ...) ::utils::COUT_("FATAL", __func__, __LINE__, format_str, ##__VA_ARGS__) //< @brief FATAL 레벨 로그 (종료)
212#define SQLOG_D(format_str, ...) ::utils::COUT_("DEBUG", __func__, __LINE__, format_str, ##__VA_ARGS__) //< @brief DEBUG 레벨 로그 (디버그 모드 전용)
213#define SQLOG_W(format_str, ...) ::utils::COUT_("WARN", __func__, __LINE__, format_str, ##__VA_ARGS__) //< @brief WARN 레벨 로그
214
215#endif // SQLOG_H // end of Logger
#define SQLOGD_BUF_SIZE
로깅 버퍼 크기
Definition log.hpp:44
#define RESOURCE_PATH
로그 파일 저장 디렉토리
Definition log.hpp:45
void ensureDirectoryExists(const std::string &dirPath)
디렉토리가 존재하지 않으면 생성합니다.
Definition log.hpp:84
std::string getLogFilePath(const std::string &level)
로그 파일 경로를 가져옵니다.
Definition log.hpp:98
void logThreadFunc()
백그라운드 로그 스레드 함수.
Definition log.hpp:108
std::string getTimeString()
현재 시스템 시간을 문자열로 반환합니다.
Definition log.hpp:66
void COUT_(const std::string &log_level, const std::string &function, int line, const char *format_str,...)
실제 로그 메시지를 포맷팅하고 출력합니다.
Definition log.hpp:143
void stopLogThread()
로그 스레드를 중지하고 종료합니다.
Definition log.hpp:200
std::mutex log_mutex
로깅 시스템 유틸리티 함수 및 전역 변수 모음.
Definition log.hpp:56
std::thread log_thread(logThreadFunc)
로그 스레드를 실행합니다.