diff --git a/.gitignore b/.gitignore index 528ad16..588f6ed 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ ./build/* Debug/* -Log/* .vs/* .vscode/* \ No newline at end of file diff --git a/Log/applog.cpp b/Log/applog.cpp new file mode 100644 index 0000000..6dbfac8 --- /dev/null +++ b/Log/applog.cpp @@ -0,0 +1,115 @@ +#include "applog.h" +#include "spdlog/spdlog.h" +#include "spdlog/async.h" +#include "spdlog/sinks/stdout_color_sinks.h" +#include "spdlog/sinks/basic_file_sink.h" +#include "spdlog/sinks/rotating_file_sink.h" +#include "stringex.h" +#include +#include + +inline std::string string_toupper(const std::string& str) +{ + std::string s = str; + transform(s.begin(), s.end(), s.begin(), toupper); + return s; +} + +void log_init(const std::string& name, bool benv) +{ + if(spdlog::get(name)) + return; + + const auto max_size = 1048576 * 5; + const auto max_files = 3; + auto file_sink = std::make_shared("logs/"+name+".log", max_size, max_files); + file_sink->set_level(spdlog::level::info); + auto logger = std::shared_ptr(new spdlog::logger("logs/" + name+".log", {file_sink})); + spdlog::register_logger(logger); +} + +void log_info(const std::string& name, const std::string& msg) +{ + if(auto log = spdlog::get("logs/" + name + ".log")) + { + log->info(msg); + log->flush(); + } +} + +void log_warn(const std::string& name, const std::string& msg) +{ + if (auto log = spdlog::get("logs/" + name + ".log")) + { + log->warn(msg); + log->flush(); + } +} + +void log_trace(const std::string& name, const std::string& msg) +{ + if (auto log = spdlog::get("logs/" + name + ".log")) + { + log->trace(msg); + log->flush(); + } +} + +void log_debug(const std::string& name, const std::string& msg) +{ + if (auto log = spdlog::get("logs/" + name + ".log")) + { + log->debug(msg); + log->flush(); + } +} + +void log_error(const std::string& name, const std::string& msg) +{ + if (auto log = spdlog::get("logs/" + name + ".log")) + { + log->error(msg); + log->flush(); + } +} + + +void log_critical(const std::string name, const std::string& msg) +{ + if (auto log = spdlog::get("logs/" + name + ".log")) + { + log->critical(msg); + log->flush(); + } +} + +bool log_set_level(const std::string& name, int type ,int level) +{ + if (auto log = spdlog::get("logs/" + name + ".log")) + { + spdlog::level::level_enum actLevel = (spdlog::level::level_enum)std::min(std::max((int)spdlog::level::trace, level), (int)spdlog::level::off); + if(type < log->sinks().size()) + log->sinks()[type]->set_level(actLevel); + else + log->set_level(actLevel); + + return true; + } + + return false; +} + +bool log_get_level(const std::string& name, int type ,int& level) +{ + if (auto log = spdlog::get("logs/" + name + ".log")) + { + if(type < log->sinks().size()) + level = log->sinks()[type]->level(); + else + level = log->level(); + + return true; + } + + return false; +} \ No newline at end of file diff --git a/Log/applog.h b/Log/applog.h new file mode 100644 index 0000000..55b9746 --- /dev/null +++ b/Log/applog.h @@ -0,0 +1,20 @@ +#pragma once +#include +#define LOG_INIT() log_init(loggername, true) +#define LOG_INITX() log_init(loggername, false) +#define LOG_INFO(X) log_info(loggername, X) +#define LOG_WARN(X) log_warn(loggername, X) +#define LOG_TRACE(X) log_trace(loggername, X) +#define LOG_DEBUG(X) log_debug(loggername, X) +#define LOG_ERROR(X) log_error(loggername, X) +#define LOG_CRITICAL(X) log_critical(loggername, X) + +void log_init(const std::string& name, bool benv); +void log_info(const std::string& name, const std::string& msg); +//void log_warn(const std::string& name, const std::string& msg); +//void log_trace(const std::string& name, const std::string& msg); +//void log_debug(const std::string& name, const std::string& msg); +//void log_error(const std::string& name, const std::string& msg); +//void log_critical(const std::string& name, const std::string& msg); +//bool log_set_level(const std::string& name, int type ,int level); +//bool log_get_level(const std::string& name, int type ,int& level); diff --git a/Log/hg_log.cpp b/Log/hg_log.cpp new file mode 100644 index 0000000..ca18cfc --- /dev/null +++ b/Log/hg_log.cpp @@ -0,0 +1,769 @@ +#include +#include +#include +#include +#include +#include +#if defined(WIN32) || defined(_WIN64) +#include +#include +#include +#include +#include +#define MKDIR(a, b) mkdir(a) +#pragma comment(lib, "imagehlp.lib") +#pragma comment(lib, "Psapi.lib") +#pragma comment(lib, "shlwapi.lib") +#else +#define MKDIR(a, b) mkdir(a, b) +#include +#include +#include +#include +#include +#include +#endif +#include +#include +#include +#include "hg_log.h" + +#define VMRSS_LINE 21 //实际物理内存使用�? +#define MAX_LOG_FILE_SIZE 10 * 1024 * 1024 +#ifdef _INTSIZEOF +#undef _INTSIZEOF +#define _INTSIZEOF(n) ((sizeof(n) + sizeof(long) - 1) & ~(sizeof(long) - 1)) +#endif + + +//extern std::string g_scanner_path; // Ending with '\\' +static std::string log_divider("=========================================================================\n"); + + +void hg_get_current_time(char* tmbuf, struct tm* t) +{ +#if defined(WIN32) || defined(_WIN64) + static long bias = -1; + static bool as_start = true; + + //if (bias == -1) + //{ + // _get_timezone(&bias); + // as_start = hg_log::ini_get("time", "adjust") != "no"; + //} +#endif + + time_t now = time(nullptr); + struct tm* l = localtime(&now); + +#if defined(WIN32) || defined(_WIN64) + long after = 0; + if (as_start && _get_timezone(&after) == 0 && + (after != bias && after != -bias)) + { + now += bias; + l = localtime(&now); + } +#endif + + if (t) + *t = *l; + if (tmbuf) + sprintf(tmbuf, "%04d-%02d-%02d %02d:%02d:%02d--->", l->tm_year + 1900, l->tm_mon + 1, l->tm_mday, l->tm_hour, l->tm_min, l->tm_sec); +} + +class log_cls +{ + typedef void(*log_to)(const char*, void*, void*); + + std::string path_file_; + FILE* file_; + log_to log_; + int level_; + std::mutex lock_; + + static log_cls* inst_; + + static FILE* create_log_file(const char* path_file, bool truncate) + { + FILE* file_ = fopen(path_file, "a+b"); + + if (file_) + { + fseek(file_, 0, SEEK_END); + if (ftell(file_) == 0) + { + unsigned char bom[] = { 0x0ef, 0x0bb, 0x0bf }; + fwrite(bom, sizeof(bom), 1, file_); + } + + std::string now(g_time_tag + hg_log::current_time() + g_time_tag); + now += truncate ? " trcated.\n" : " started.\n"; + now.insert(0, log_divider); + fwrite(now.c_str(), 1, now.length(), file_); + } + + return file_; + } + static void log_none(const char* info, void* param, void* param2) + {} + static void log_consonle(const char* info, void* param, void* param2) + { + printf(info); + } + static void log_file(const char* info, void* param, void* param2) + { + FILE** file = (FILE**)param; + + if(*file == nullptr) + *file = create_log_file(((std::string*)param2)->c_str(), false); + + if (*file) + { + fwrite(info, 1, strlen(info), *file); + fflush(*file); + if (ftell(*file) >= MAX_LOG_FILE_SIZE) + { + fclose(*file); + remove(((std::string*)param2)->c_str()); + *file = create_log_file(((std::string*)param2)->c_str(), true); + } + } + } + + +protected: + log_cls() : path_file_(""), file_(0), log_(&log_cls::log_consonle) + {} + ~log_cls() + { + if (file_) + { + fclose(file_); + file_ = 0; + } + } + +public: + static std::string g_time_tag; + static log_cls* instance(void) + { + if (!log_cls::inst_) + log_cls::inst_ = new log_cls(); + + return log_cls::inst_; + } + static void clear(void) + { + if (log_cls::inst_) + { + delete log_cls::inst_; + log_cls::inst_ = nullptr; + } + } + + int set_log_type(int type, void* param) + { + int ret = 0; + + if (file_) + { + fclose(file_); + file_ = 0; + } + log_ = NULL; + + if (type == LOG_TYPE_NONE) + log_ = &log_cls::log_none; + else if(type == LOG_TYPE_CONSOLE) + log_ = &log_cls::log_consonle; + else if (type == LOG_TYPE_FILE) + { + log_ = &log_cls::log_file; + + ret = -1; + if (param) + { + path_file_ = (char*)param; + file_ = create_log_file(path_file_.c_str(), false); + if (file_) + ret = 0; + } + } + + if(ret != 0) + log_ = &log_cls::log_none; + + return ret; + } + void set_log_level(int level) + { + level_ = level; + } + bool is_log_level_enabled(int level) + { + return level >= level_; + } + + void log(const char* info) + { + std::lock_guard lock(lock_); + + log_(info, &file_, &path_file_); + } + std::string get_log_file_path(bool copy) + { + std::string file(""); + + if (log_ == &log_cls::log_file && file_) + { + file = path_file_; + + if (copy) + { + file += ".txt"; + + FILE* dst = fopen(file.c_str(), "wb"); + + if (!dst) + file = ""; + else + { + std::lock_guard lock(lock_); + char buf[1024] = { 0 }; + size_t l = 0; + + fseek(file_, 0, SEEK_SET); + while ((l = fread(buf, 1, sizeof(buf), file_))) + fwrite(buf, 1, l, dst); + fclose(dst); + } + } + } + + return file; + } + void clear_log(void) + { + if (log_ == &log_cls::log_file && file_) + { + std::lock_guard lock(lock_); + + fclose(file_); + remove(path_file_.c_str()); + file_ = create_log_file(path_file_.c_str(), true); + } + } +}; +log_cls* log_cls::inst_ = NULL; +std::string log_cls::g_time_tag = "====="; + +#ifdef EXPORT_AS_C +extern "C" +{ +#endif + namespace hg_log + { + static log_callback lcb_ = NULL; + + typedef struct _find_file + { + std::string pattern; + std::string found; + }FINDFILE, * LPFF; + static bool on_found(const char* file, void* param) + { + LPFF lpff = (LPFF)param; + char pth = PATH_SEPARATOR[0]; + const char* name = strrchr(file, pth); + + if (name++ == nullptr) + name = file; + + std::string lc(name); + str_tolower(lc); + if (lc.find(lpff->pattern) != std::string::npos) + { + lpff->found = file; + return false; + } + + return true; + } +#if defined(WIN32) || defined(_WIN64) + static std::string u2a(const wchar_t* u, UINT cp = CP_ACP) + { + std::string a(""); + + if (u) + { + char stack[256] = { 0 }, * ansi = NULL; + int len = 0; + + len = WideCharToMultiByte(cp, 0, u, lstrlenW(u), NULL, 0, NULL, NULL); + ansi = new char[len + 2]; + len = WideCharToMultiByte(cp, 0, u, lstrlenW(u), ansi, len, NULL, NULL); + ansi[len--] = 0; + a = ansi; + delete[] ansi; + } + + return a; + } + static int enum_files(const char* dir, bool recursive, bool(*found_file)(const char* path_file, void* param), void* param) + { + int ret = 0; + HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId()); + MODULEENTRY32W pei = { 0 }; + + if (h == INVALID_HANDLE_VALUE) + ret = GetLastError(); + else + { + pei.dwSize = sizeof(pei); + if (Module32FirstW(h, &pei)) + { + do + { + std::string ansi(u2a(pei.szExePath)); + if (!found_file(ansi.c_str(), param)) + break; + pei.dwSize = sizeof(pei); + } while (Module32NextW(h, &pei)); + } + CloseHandle(h); + } + + return ret; + } +#else + static std::string link_file(const char* lnk) + { + char path[256] = { 0 }; + int len = readlink(lnk, path, sizeof(path) - 1); + + return len > 0 ? path : lnk; + } + static int enum_files(const char* dir, bool recursive, bool(*found_file)(const char* path_file, void* param), void* param) + { + int ret = 0; + DIR* pdir = nullptr; + struct dirent* ent = nullptr; + + pdir = opendir(dir); + if (!pdir) + return errno; + + while ((ent = readdir(pdir))) + { + if (ent->d_type & DT_DIR) + { + if (recursive) + { + if (strcmp(ent->d_name, ".") && strcmp(ent->d_name, "..")) + { + std::string sub(dir); + sub += "/"; + sub += ent->d_name; + ret = enum_files(sub.c_str(), recursive, found_file, param); + if (ret == 0x5e17) + break; + } + } + } + else + { + std::string file(dir); + + file += "/"; + file += ent->d_name; + if (!found_file(link_file(file.c_str()).c_str(), param)) + { + ret = 0x5e17; + break; + } + } + } + + return ret; + } + +#endif + std::string get_scanimage_ver() + { + #if defined(WIN32) || defined(_WIN64) + return ""; + #else + FILE* fp = NULL; + char buf[128] = { 0 }; + fp = popen("scanimage -V", "r"); + if (!fp) + return ""; + + int ret = fread(buf, 1, sizeof(buf) - 1, fp); + if(ret<1) + return ""; + + pclose(fp); + std::string str = buf; + return str.substr(str.size()-7); + #endif + } + void clear_log(void) + { + log_cls::instance()->clear_log(); + } + //static std::string get_scanimage_ver() + //{ + // FILE* fp = popen("scanimage -V","r"); + // if (!fp) + // { + // return ""; + // } + // long len = 0; + // fseek(fp, 0, SEEK_END); + // len = ftell(fp); + // fseek(fp, 0, SEEK_SET); + // char* buf = new char[len]; + // if (!buf) + // { + // return ""; + // } + // int ret = fread(buf, 1, sizeof(buf) - 1, fp); + // pclose(); + //} + std::string format_ptr(void* ptr) + { + char buf[40]; + + if (sizeof(ptr) == sizeof(int)) + { + sprintf(buf, "0x%08x", ptr); + } + else + { + unsigned int* n = (unsigned int*)&ptr; + sprintf(buf, "0x%x%08x", n[1], n[0]); + } + + return buf; + } + std::string format_current_thread_id(void) + { +#if defined(WIN32) || defined(_WIN64) + return format_ptr((void*)GetCurrentThreadId()); +#else + return format_ptr((void*)pthread_self()); +#endif + } + std::string current_time(void) + { + char buf[40] = { 0 }; + + hg_get_current_time(buf,nullptr); + + return buf; + } + std::string format_size(unsigned long size) + { + char buf[40]; + + if (size > 1024 * 1024 * 1024) + { + double d = size; + + d /= 1024 * 1024 * 1024; + sprintf(buf, "%.2fGB", d); + } + else if (size > 1024 * 1024) + { + double d = size; + + d /= 1024 * 1024; + sprintf(buf, "%.2fMB", d); + } + else if (size > 1024) + { + double d = size; + + d /= 1024; + sprintf(buf, "%.1fKB", d); + } + else + { + sprintf(buf, "%u bytes", (unsigned int)size); + } + + return buf; + } + std::string u2utf8(const wchar_t* u) + { + std::string utf8(""); + +#if defined(WIN32) || defined(_WIN64) + utf8 = u2a(u, CP_UTF8); +#else +#endif + return utf8; + } + std::string pe_path(std::string* name) + { +#if defined(WIN32) || defined(_WIN64) + wchar_t path[MAX_PATH] = { 0 }, * last = NULL; + + GetModuleFileNameW(NULL, path, _countof(path) - 1); + last = wcsrchr(path, L'\\'); + if (last) + { + if (name) + *name = u2utf8(last + 1); + *last = 0; + } + + return u2utf8(path); +#else + char path[256] = { 0 }; + int len = readlink("/proc/self/exe", path, sizeof(path) - 1); + + if (len > 0 && len < sizeof(path)) + { + for (--len; len > 0; --len) + { + if (path[len] == '/') + { + path[len] = 0; + if (name) + *name = path + len + 1; + break; + } + } + } + + return path; +#endif + } + unsigned long long available_memory(void) + { +#if defined(WIN32) || defined(_WIN64) + MEMORYSTATUSEX ms; + + if (GlobalMemoryStatusEx(&ms)) + return ms.ullAvailPhys; + else + return -1; +#else + struct sysinfo si; + if (sysinfo(&si) == 0) + return si.freeram * si.mem_unit; +#endif + } + void str_tolower(std::string& str) + { + std::transform(str.begin(), str.end(), str.begin(), tolower); + } + bool create_folder(const char* fodler) + { + return MKDIR(fodler, S_IREAD | S_IWRITE | S_IEXEC) == 0 || errno == EEXIST; + } + + std::string get_module_full_path(const char* module_part_name) + { + char path[128] = { 0 }; + FINDFILE ff; + + ff.pattern = module_part_name; + str_tolower(ff.pattern); +#if defined(WIN32) || defined(_WIN64) +#else + sprintf(path, "/proc/%u/map_files/", getpid()); +#endif + enum_files(path, false, on_found, &ff); + + return ff.found; + } + std::string get_scanner_path(void) + { + return ""; + } + unsigned int get_page_size(unsigned int* map_unit) + { + unsigned int ps = 1024; +#if defined(WIN32) || defined(_WIN64) + SYSTEM_INFO si = { 0 }; + + GetSystemInfo(&si); + ps = si.dwPageSize; + if (map_unit) + *map_unit = si.dwAllocationGranularity; +#else + ps = sysconf(_SC_PAGESIZE); + if(ps < 1024 || (ps & 0x0fe0000ff)) // nKB && < 16MB + ps = getpagesize(); + if (map_unit) + *map_unit = ps; +#endif + if (ps < 1024 || (ps & 0x0fe0000ff)) // nKB && < 16MB + ps = 1024; + + return ps; + } + static int get_log_config(const std::string& root, hg_log_type* type, std::string* path) + { + std::string me(root + PATH_SEPARATOR + "config" + PATH_SEPARATOR + "debug.cfg"); + int lv = LOG_LEVEL_ALL; + hg_log_type tp = LOG_TYPE_FILE; + + if (!type) + type = &tp; + *type = LOG_TYPE_FILE; + create_folder((root + PATH_SEPARATOR + "config").c_str()); + + return lv; + } + std::string local_data_path(void) + { + static std::string local_data_path("."); + static bool load_first = true; + + + std::string home(local_data_path); + create_folder(home.c_str()); + + return home; + } + + std::string log_file_path(void) + { + return log_cls::instance()->get_log_file_path(true); + } + + int init(void) + { + char* file = nullptr; + std::string path(""); + hg_log_type type = LOG_TYPE_FILE; + int level = get_log_config(local_data_path(), &type, &path); + + if (type == LOG_TYPE_FILE) + { + std::string name(""), + paths[] = { local_data_path(), pe_path(&name), get_scanner_path()}; + int ind = 0; + + if (!path.empty() && create_folder(path.c_str())) + ind = sizeof(paths) / sizeof(paths[0]) + 2; + + for (; ind < sizeof(paths) / sizeof(paths[0]); ++ind) + { + path = paths[ind] + PATH_SEPARATOR + "Log"; + if (create_folder(path.c_str())) + break; + } + if(ind == sizeof(paths) / sizeof(paths[0])) + { + //VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "# Try PE, scanner and temporary path failed(%d), log to console\n", errno); + type = LOG_TYPE_CONSOLE; + } + + if (type == LOG_TYPE_FILE) + { + if (name.empty()) + path += std::string(PATH_SEPARATOR) + "scanner.log"; + else + path += PATH_SEPARATOR + name + ".log"; + file = &path[0]; + //VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "# Log to file: '%s'\n", path.c_str()); + } + } + log_cls::instance()->set_log_level(level); + + return log_cls::instance()->set_log_type(type, file); + } + void unint(void) + { + std::string now(log_cls::g_time_tag + hg_log::current_time() + log_cls::g_time_tag + " exited.\n"); + log(now.c_str()); + log((log_divider + "\n\n\n\n").c_str()); + log_cls::clear(); + } + void log(int level, const char* info) + { + if (lcb_) + lcb_(level, info); + else if (log_cls::instance()->is_log_level_enabled(level)) + log_cls::instance()->log(info); + } + bool is_log_level_enabled(int level) + { + return log_cls::instance()->is_log_level_enabled(level); + } + void log(const char* info) + { + log_cls::instance()->log(info); + } + float GetMemoryUsage(int pid) + { +#ifdef WIN32 + uint64_t mem = 0, vmem = 0; + PROCESS_MEMORY_COUNTERS pmc; + + HANDLE process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); + if (GetProcessMemoryInfo(process, &pmc, sizeof(pmc))) + { + mem = pmc.WorkingSetSize; + vmem = pmc.PagefileUsage; + } + CloseHandle(process); + + return mem / 1024.0 / 1024.0;//byte TO MB + +#else + char file_name[64] = { 0 }; + FILE* fd; + char line_buff[512] = { 0 }; + sprintf(file_name, "/proc/%d/status", pid); + + fd = fopen(file_name, "r"); + if (nullptr == fd) + return 0; + + char name[64]; + int vmrss = 0; + for (int i = 0; i < VMRSS_LINE - 1; i++) + fgets(line_buff, sizeof(line_buff), fd); + + fgets(line_buff, sizeof(line_buff), fd); + sscanf(line_buff, "%s %d", name, &vmrss); + fclose(fd); + return vmrss / 1024.0;//KB TO MB +#endif +} + float GetAppMemoryUsage() + { + return GetMemoryUsage(getpid()); + } + + const char* lang_load(uint32_t id) + { + int err = 0; + const char *lang ="unused "; + if (err != 0) + { + return ""; + } + return lang; + } + + + } +#ifdef EXPORT_AS_C +} +#endif + +#if defined(WIN32) || defined(_WIN64) +void hg_debug_log(int level, const char* info) +{ + hg_log::log(level, info); +} +#endif + diff --git a/Log/hg_log.h b/Log/hg_log.h new file mode 100644 index 0000000..60098d7 --- /dev/null +++ b/Log/hg_log.h @@ -0,0 +1,82 @@ +// this file is include huagao logging tools +// +// created: 2022-02-09 +// + +#pragma once + +#include +#if defined(WIN32) || defined(_WIN64) +#define bzero(a, l) memset(a, 0, l) +#define PATH_SEPARATOR "\\" +#define DLL_EXTESION ".dll" +#define STRICMP stricmp +#else +#include +#define PATH_SEPARATOR "/" +#define DLL_EXTESION ".so" +#define STRICMP strcasecmp +#endif + +enum hg_log_type +{ + LOG_TYPE_NONE = 0, // no logging + LOG_TYPE_CONSOLE, // print to console + LOG_TYPE_FILE, // write log into file + LOG_TYPE_CALLBACK, // invoke callback log_callback +}; + +enum log_level +{ + LOG_LEVEL_ALL = 0, + LOG_LEVEL_DEBUG_INFO, + LOG_LEVEL_WARNING, + LOG_LEVEL_FATAL, +}; + +typedef void (*log_callback)(int, const char* info); + +#ifdef EXPORT_AS_C +extern "C" +{ +#endif + namespace hg_log + { + std::string format_ptr(void* ptr); + std::string format_current_thread_id(void); + std::string current_time(void); + std::string format_size(unsigned long size); + std::string u2utf8(const wchar_t* u); + std::string pe_path(std::string* name = nullptr); + std::string get_module_full_path(const char* module_part_name); + std::string get_scanner_path(void); + std::string local_data_path(void); + //std::string temporary_path(void); + std::string log_file_path(void); + std::string get_scanimage_ver(); + void clear_log(void); + float GetMemoryUsage(int pid); + float GetAppMemoryUsage(); + const char* lang_load(uint32_t id); + unsigned int get_page_size(unsigned int* map_unit = nullptr); + unsigned long long available_memory(void); + void str_tolower(std::string& str); + bool create_folder(const char* fodler); + + //std::string ini_get(const char* app, const char* key); + // void ini_set(const char* app, const char* key, const char* val); + + // Function: initialize the logging type and level + // + // Return: 0 - success, or -1 in LOG_TYPE_FILE and log_file cannot be created + int init(void); + void unint(void); + + void log(int level, const char* info); + bool is_log_level_enabled(int level); + void log(const char* info); + } +#ifdef EXPORT_AS_C +} +#endif +