code_device/hgdriver/wrapper/hg_log.cpp

866 lines
18 KiB
C++
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <vector>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <stdarg.h>
#if defined(WIN32) || defined(_WIN64)
#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")
#else
#define MKDIR(a, b) mkdir(a, b)
#include <pthread.h>
#include <sys/sysinfo.h>
#include <unistd.h>
#include <dirent.h>
#include <fcntl.h>
#include <sys/stat.h>
#endif
#include <time.h>
#include "../wrapper/hg_log.h"
#include <algorithm>
#include <mutex>
#include "ini_file.h"
#define VMRSS_LINE 21 //实际物ç<C2A9>†å†…存使用çŽ?
#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");
class log_cls
{
typedef void(*log_to)(const char*, void*, void*);
std::string path_file_;
FILE* file_;
log_to log_;
int level_;
log_callback lcb_;
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 ? " truncated.\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), level_(LOG_LEVEL_ALL), lcb_(NULL)
{}
~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;
}
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)
{
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;
}
}
else if (type == LOG_TYPE_CALLBACK)
{
lcb_ = (log_callback)param;
}
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<std::mutex> 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<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);
}
}
};
log_cls* log_cls::inst_ = NULL;
std::string log_cls::g_time_tag = "=====";
#ifdef EXPORT_AS_C
extern "C"
{
#endif
namespace hg_log
{
static simple_ini ini_;
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);
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);
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;
}
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)
{
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;
}
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;
if (ini_.load(me.c_str()) == 0)
{
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
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
home += "HanvonScan";
#elif defined(OEM_LISICHENG)
home += "LanxumScan";
#elif defined(OEM_CANGTIAN)
home += "CumTennScan";
#elif defined(OEM_ZHONGJING)
home += "MicrotekScan";
#elif defined(OEM_ZIGUANG)
home += "UniScan";
#elif defined(OEM_DELI)
home += "DeliScan";
#elif defined(OEM_NEUTRAL)
home += "NeuScan";
#else
home += "HuaGoScan";
#endif;
create_folder(home.c_str());
return home;
}
std::string temporary_path(void)
{
return simple_ini::temporary_path();
}
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(), 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;
}
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 = lang_load_string(id, &err);
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