code_device/hgdriver/wrapper/hg_log.cpp

866 lines
18 KiB
C++
Raw Normal View History

2022-05-03 03:56:07 +00:00
#include <vector>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <stdarg.h>
#if defined(WIN32) || defined(_WIN64)
2022-05-03 03:56:07 +00:00
#include <Windows.h>
#include <direct.h>
#include <Psapi.h>
#include <Tlhelp32.h>
#include <imagehlp.h>
#define MKDIR(a, b) mkdir(a)
#pragma comment(lib, "imagehlp.lib")
#pragma comment(lib, "Psapi.lib")
#pragma comment(lib, "shlwapi.lib")
2022-05-03 03:56:07 +00:00
#else
#define MKDIR(a, b) mkdir(a, b)
2022-05-03 03:56:07 +00:00
#include <pthread.h>
#include <sys/sysinfo.h>
#include <unistd.h>
#include <dirent.h>
#include <fcntl.h>
#include <sys/stat.h>
2022-05-03 03:56:07 +00:00
#endif
#include <time.h>
#include "../wrapper/hg_log.h"
#include <algorithm>
2022-07-20 06:57:26 +00:00
#include <mutex>
#include "ini_file.h"
2023-08-07 07:16:03 +00:00
#define VMRSS_LINE 21 //实际物理内存使用<E4BDBF><E794A8>?
2023-05-10 02:14:24 +00:00
#define MAX_LOG_FILE_SIZE 10 * 1024 * 1024
2022-05-03 03:56:07 +00:00
#ifdef _INTSIZEOF
#undef _INTSIZEOF
#define _INTSIZEOF(n) ((sizeof(n) + sizeof(long) - 1) & ~(sizeof(long) - 1))
#endif
extern std::string g_scanner_path; // Ending with '\\'
2022-11-17 02:26:02 +00:00
static std::string log_divider("=========================================================================\n");
class log_cls
2022-05-03 03:56:07 +00:00
{
typedef void(*log_to)(const char*, void*, void*);
2022-05-03 03:56:07 +00:00
std::string path_file_;
FILE* file_;
log_to log_;
int level_;
log_callback lcb_;
2022-07-20 06:57:26 +00:00
std::mutex lock_;
2022-05-03 03:56:07 +00:00
static log_cls* inst_;
2022-05-03 03:56:07 +00:00
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);
2022-11-17 02:26:02 +00:00
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);
2023-12-08 00:49:10 +00:00
now += truncate ? " truncated.\n" : " started.\n";
2022-11-17 02:26:02 +00:00
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)
2022-05-03 03:56:07 +00:00
{}
static void log_consonle(const char* info, void* param, void* param2)
2022-05-03 03:56:07 +00:00
{
printf(info);
}
static void log_file(const char* info, void* param, void* param2)
2022-05-03 03:56:07 +00:00
{
FILE** file = (FILE**)param;
if(*file == nullptr)
*file = create_log_file(((std::string*)param2)->c_str(), false);
2022-05-03 03:56:07 +00:00
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);
}
}
2022-05-03 03:56:07 +00:00
}
2022-05-03 03:56:07 +00:00
protected:
log_cls() : path_file_(""), file_(0), log_(&log_cls::log_consonle), level_(LOG_LEVEL_ALL), lcb_(NULL)
2022-05-03 03:56:07 +00:00
{}
~log_cls()
2022-05-03 03:56:07 +00:00
{
if (file_)
{
fclose(file_);
file_ = 0;
}
}
public:
static std::string g_time_tag;
static log_cls* instance(void)
2022-05-03 03:56:07 +00:00
{
if (!log_cls::inst_)
log_cls::inst_ = new log_cls();
2022-05-03 03:56:07 +00:00
return log_cls::inst_;
2022-05-03 03:56:07 +00:00
}
2023-08-07 07:16:03 +00:00
static void clear(void)
{
if (log_cls::inst_)
{
delete log_cls::inst_;
log_cls::inst_ = nullptr;
}
}
2022-05-03 03:56:07 +00:00
int set_log_type(int type, void* param)
{
int ret = 0;
if (file_)
{
fclose(file_);
file_ = 0;
}
lcb_ = NULL;
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)
2022-05-03 03:56:07 +00:00
{
log_ = &log_cls::log_file;
2022-05-03 03:56:07 +00:00
ret = -1;
if (param)
{
path_file_ = (char*)param;
file_ = create_log_file(path_file_.c_str(), false);
2022-05-03 03:56:07 +00:00
if (file_)
ret = 0;
}
}
else if (type == LOG_TYPE_CALLBACK)
2022-05-03 03:56:07 +00:00
{
lcb_ = (log_callback)param;
}
if(ret != 0)
log_ = &log_cls::log_none;
2022-05-03 03:56:07 +00:00
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)
{
2022-07-20 06:57:26 +00:00
std::lock_guard<std::mutex> lock(lock_);
log_(info, &file_, &path_file_);
2022-05-03 03:56:07 +00:00
}
2022-07-20 06:57:26 +00:00
std::string get_log_file_path(bool copy)
{
std::string file("");
if (log_ == &log_cls::log_file && file_)
2022-07-20 06:57:26 +00:00
{
file = path_file_;
if (copy)
{
file += ".txt";
FILE* dst = fopen(file.c_str(), "wb");
if (!dst)
file = "";
else
{
std::lock_guard<std::mutex> 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<std::mutex> lock(lock_);
fclose(file_);
remove(path_file_.c_str());
file_ = create_log_file(path_file_.c_str(), true);
}
}
2022-05-03 03:56:07 +00:00
};
log_cls* log_cls::inst_ = NULL;
std::string log_cls::g_time_tag = "=====";
2022-05-03 03:56:07 +00:00
#ifdef EXPORT_AS_C
extern "C"
{
#endif
namespace hg_log
{
static simple_ini ini_;
2022-05-03 03:56:07 +00:00
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;
}
static bool save_dir_files(const char* path_file, void* param)
{
((std::vector<std::string>*)param)->push_back(path_file);
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;
if (!dir || *dir == 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);
}
}
else
{
WIN32_FIND_DATAA wfd = { 0 };
HANDLE h = FindFirstFileA((std::string(dir) + "\\*").c_str(), &wfd);
if (h == INVALID_HANDLE_VALUE)
ret = GetLastError();
else
{
do
{
if (strcmp(wfd.cFileName, ".") == 0 || strcmp(wfd.cFileName, "..") == 0)
continue;
if (!found_file((std::string(dir) + "\\" + wfd.cFileName).c_str(), param))
{
ret = ECANCELED;
break;
}
if ((wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && recursive)
{
ret = enum_files((std::string(dir) + "\\" + wfd.cFileName).c_str(), recursive, found_file, param);
if (ret == ECANCELED)
break;
}
} while (FindNextFileA(h, &wfd));
FindClose(h);
}
}
return ret;
}
#else
static std::string link_file(const char* lnk)
{
char path[256] = { 0 };
int len = readlink(lnk, path, sizeof(path) - 1);
2023-02-03 04:00:50 +00:00
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 "";
2023-01-18 02:35:40 +00:00
#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();
}
2022-12-13 10:13:46 +00:00
//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();
//}
2022-05-03 03:56:07 +00:00
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)
2022-05-03 03:56:07 +00:00
return format_ptr((void*)GetCurrentThreadId());
#else
return format_ptr((void*)pthread_self());
#endif
}
std::string current_time(void)
{
2022-11-08 03:21:50 +00:00
char buf[40] = { 0 };
2022-05-03 03:56:07 +00:00
2023-02-13 08:59:54 +00:00
hg_get_current_time(buf);
2022-05-03 03:56:07 +00:00
return buf;
}
std::string format_size(unsigned long size)
{
char buf[40];
if (size > 1024 * 1024 * 1024)
{
double d = size;
2022-05-03 03:56:07 +00:00
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);
2022-05-03 03:56:07 +00:00
#else
#endif
return utf8;
}
std::string pe_path(std::string* name)
{
#if defined(WIN32) || defined(_WIN64)
2022-05-03 03:56:07 +00:00
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 };
2022-05-03 03:56:07 +00:00
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)
2022-05-03 03:56:07 +00:00
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)
2022-05-03 03:56:07 +00:00
{
return MKDIR(fodler, S_IREAD | S_IWRITE | S_IEXEC) == 0 || errno == EEXIST;
2022-05-03 03:56:07 +00:00
}
void get_foler_files(const char* folder, std::vector<std::string>& files, bool recursive)
{
enum_files(folder, recursive, save_dir_files, &files);
}
std::string ini_get(const char* app, const char* key)
2022-05-03 03:56:07 +00:00
{
return ini_.get(app, key);
}
void ini_set(const char* app, const char* key, const char* val)
{
ini_.set(app, key, val);
}
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 g_scanner_path;
}
2022-06-16 08:03:55 +00:00
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;
2022-06-16 08:03:55 +00:00
if (map_unit)
*map_unit = si.dwAllocationGranularity;
#else
ps = sysconf(_SC_PAGESIZE);
if(ps < 1024 || (ps & 0x0fe0000ff)) // nKB && < 16MB
ps = getpagesize();
2022-06-16 08:03:55 +00:00
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)
{
2022-10-11 06:41:49 +00:00
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;
if (ini_.load(me.c_str()) == 0)
2022-05-03 03:56:07 +00:00
{
std::string val(ini_.get("log", "type"));
if (val == "console")
*type = LOG_TYPE_CONSOLE;
else if (val == "none")
*type = LOG_TYPE_NONE;
else
*type = LOG_TYPE_FILE;
if (*type == LOG_TYPE_FILE && path)
{
*path = ini_.get("log", "path");
}
val = ini_.get("log", "level");
if (val == "debug")
lv = LOG_LEVEL_DEBUG_INFO;
else if (val == "warning")
lv = LOG_LEVEL_WARNING;
else if (val == "fatal")
lv = LOG_LEVEL_FATAL;
}
else
2022-10-11 06:41:49 +00:00
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;
if (load_first)
{
simple_ini first;
load_first = false;
if (first.load((get_scanner_path() + "first.cfg").c_str()) == 0)
{
std::string env = first.get("constraints", "local_data_path");
if (env.length())
local_data_path = env;
}
}
std::string home(local_data_path);
if (home.empty())
{
#if defined(WIN32) || defined(_WIN64)
std::string env("LOCALAPPDATA"), lead("");
#else
std::string env("HOME"), lead(".");
#endif
char* tmp = getenv(env.c_str());
if (tmp)
home = tmp;
home += PATH_SEPARATOR + lead;
}
#ifdef OEM_HANWANG
2022-06-06 10:29:09 +00:00
home += "HanvonScan";
#elif defined(OEM_LISICHENG)
2022-06-06 10:29:09 +00:00
home += "LanxumScan";
2023-01-17 07:07:58 +00:00
#elif defined(OEM_CANGTIAN)
home += "CumTennScan";
2023-02-01 06:52:36 +00:00
#elif defined(OEM_ZHONGJING)
home += "MicrotekScan";
#elif defined(OEM_ZIGUANG)
home += "UniScan";
2023-07-18 08:47:13 +00:00
#elif defined(OEM_DELI)
home += "DeliScan";
2023-08-04 02:23:11 +00:00
#elif defined(OEM_NEUTRAL)
home += "NeuScan";
#else
home += "HuaGoScan";
#endif;
create_folder(home.c_str());
return home;
}
2022-06-08 01:31:35 +00:00
std::string temporary_path(void)
{
return simple_ini::temporary_path();
}
2022-07-20 06:57:26 +00:00
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);
2022-05-03 03:56:07 +00:00
if (type == LOG_TYPE_FILE)
{
std::string name(""),
2022-06-08 01:31:35 +00:00
paths[] = { local_data_path(), pe_path(&name), get_scanner_path(), temporary_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;
}
2022-05-03 03:56:07 +00:00
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());
}
2022-05-03 03:56:07 +00:00
}
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());
2022-11-17 02:26:02 +00:00
log((log_divider + "\n\n\n\n").c_str());
2023-08-07 07:16:03 +00:00
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);
2022-05-03 03:56:07 +00:00
}
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);
2022-11-24 09:21:41 +00:00
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 = lang_load_string(id, &err);
if (err != 0)
{
return "";
}
return lang;
}
2022-05-03 03:56:07 +00:00
}
#ifdef EXPORT_AS_C
}
#endif
#if defined(WIN32) || defined(_WIN64)
void hg_debug_log(int level, const char* info)
2022-05-03 03:56:07 +00:00
{
hg_log::log(level, info);
}
#endif