code_device/hgdriver/wrapper/hg_log.cpp

496 lines
9.6 KiB
C++

#include <vector>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <stdarg.h>
#ifdef WIN32
#include <Windows.h>
#include <direct.h>
#define MKDIR(a, b) mkdir(a)
#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 "ini_file.h"
#define MAX_LOG_FILE_SIZE 100 * 1024 * 1024
#ifdef _INTSIZEOF
#undef _INTSIZEOF
#define _INTSIZEOF(n) ((sizeof(n) + sizeof(long) - 1) & ~(sizeof(long) - 1))
#endif
#ifdef WIN32
extern std::string g_module_path; // Ending with '\\'
#endif
class log_cls
{
typedef void(*log_to)(const char*, void*);
std::string path_file_;
FILE* file_;
log_to log_;
int level_;
log_callback lcb_;
static log_cls* inst_;
static void log_none(const char* info, void* param)
{}
static void log_consonle(const char* info, void* param)
{
printf(info);
}
static void log_file(const char* info, void* param)
{
FILE* file = (FILE*)param;
fwrite(info, 1, strlen(info), file);
fflush(file);
if (ftell(file) >= MAX_LOG_FILE_SIZE)
fseek(file, 0, SEEK_SET);
}
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 log_cls* instance(void)
{
if (!log_cls::inst_)
log_cls::inst_ = new log_cls();
return log_cls::inst_;
}
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_ = fopen(path_file_.c_str(), "wb");
if (file_)
{
unsigned char bom[] = { 0x0ef, 0x0bb, 0x0bf };
fwrite(bom, sizeof(bom), 1, 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)
{
log_(info, (void*)file_);
}
};
log_cls* log_cls::inst_ = NULL;
#ifdef EXPORT_AS_C
extern "C"
{
#endif
namespace hg_log
{
static log_callback lcb_ = NULL;
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)
{
#ifdef WIN32
return format_ptr((void*)GetCurrentThreadId());
#else
return format_ptr((void*)pthread_self());
#endif
}
std::string current_time(void)
{
char buf[40];
time_t t = time(NULL);
tm* l = localtime(&t);
sprintf(buf, "%d-%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);
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("");
#ifdef WIN32
if (u)
{
char stack[256] = { 0 }, * ansi = NULL;
int len = 0;
len = WideCharToMultiByte(CP_UTF8, 0, u, lstrlenW(u), NULL, 0, NULL, NULL);
ansi = new char[len + 2];
len = WideCharToMultiByte(CP_UTF8, 0, u, lstrlenW(u), ansi, len, NULL, NULL);
ansi[len--] = 0;
utf8 = ansi;
delete[] ansi;
}
#else
#endif
return utf8;
}
std::string pe_path(std::string* name)
{
#ifdef WIN32
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)
{
#ifdef WIN32
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
}
static void str_tolower(std::string& str)
{
std::transform(str.begin(), str.end(), str.begin(), tolower);
}
#ifndef WIN32
typedef struct _find_file
{
std::string pattern;
std::string found;
}FINDFILE, * LPFF;
static std::string link_file(const char* lnk)
{
char path[256] = { 0 };
int len = readlink(lnk, path, sizeof(path) - 1);
return path;
}
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;
}
static bool on_found(const char* file, void* param)
{
LPFF lpff = (LPFF)param;
const char* name = strrchr(file, '/');
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;
}
#endif
static std::string get_self_path(void)
{
#ifdef WIN32
return g_module_path;
#else
char path[128] = { 0 };
FINDFILE ff;
size_t pos = 0;
ff.pattern = GET_BACKEND_NAME;
ff.pattern += ".so";
str_tolower(ff.pattern);
sprintf(path, "/proc/%u/map_files/", getpid());
enum_files(path, false, on_found, &ff);
pos = ff.found.rfind('/');
if (pos++ == std::string::npos)
ff.found += "/";
else
ff.found.erase(pos);
return ff.found;
#endif
}
static int get_log_config(const std::string& self_path, hg_log_type* type, std::string* path)
{
std::string me(self_path + "/configs/scanner.conf");
simple_ini ini;
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;
}
return lv;
}
int init(void)
{
char* file = nullptr;
std::string me(get_self_path()), path("");
hg_log_type type = LOG_TYPE_FILE;
int level = get_log_config(me, &type, &path);
if (type == LOG_TYPE_FILE)
{
if (path.empty())
path = me;
path += "/log";
if (MKDIR(path.c_str(), S_IREAD | S_IWRITE | S_IEXEC) &&
errno != EEXIST)
{
VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "Create log-folder '%s' failed(%d), now try temporary directory\n", path.c_str(), errno);
path = simple_ini::temporary_path() + "/log";
if (MKDIR(path.c_str(), S_IREAD | S_IWRITE | S_IEXEC) &&
errno != EEXIST)
{
VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "create temporary directory '%s' failed(%d), log to console\n", path.c_str(), errno);
type = LOG_TYPE_CONSOLE;
}
}
if (type == LOG_TYPE_FILE)
{
std::string name("");
pe_path(&name);
if (name.empty())
path += "/scanner.log";
else
path += "/" + 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 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);
}
}
#ifdef EXPORT_AS_C
}
#endif
#ifdef WIN32
void hg_debug_log(int level, const char* info)
{
hg_log::log(level, info);
}
#endif